diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..11ebf4e4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +tab_width = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.js] +quote_type = single + +[{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.js,*.java,*.go,*.rs,*.php,*.ng,*.jsx,*.ts,*.d,*.cs,*.swift}] +curly_bracket_next_line = false +spaces_around_operators = true +spaces_around_brackets = outside +# close enough to 1TB +indent_brace_style = K&R diff --git a/.env.template b/.env.template new file mode 100644 index 00000000..b68daaff --- /dev/null +++ b/.env.template @@ -0,0 +1,15 @@ +# Available providers: bigcommerce, shopify, swell +COMMERCE_PROVIDER= + +BIGCOMMERCE_STOREFRONT_API_URL= +BIGCOMMERCE_STOREFRONT_API_TOKEN= +BIGCOMMERCE_STORE_API_URL= +BIGCOMMERCE_STORE_API_TOKEN= +BIGCOMMERCE_STORE_API_CLIENT_ID= +BIGCOMMERCE_CHANNEL_ID= + +NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN= +NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN= + +NEXT_PUBLIC_SWELL_STORE_ID= +NEXT_PUBLIC_SWELL_PUBLIC_KEY= diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..22f1bf4f --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +.next/ +out/ + +# production +/build + +# misc +.DS_Store +*.pem +.idea + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..105738ca --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +node_modules +.next +public \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..e1076edf --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..c83e2634 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["esbenp.prettier-vscode"] +} diff --git a/README.md b/README.md new file mode 100644 index 00000000..c4675229 --- /dev/null +++ b/README.md @@ -0,0 +1,142 @@ +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-description=An%20all-in-one%20starter%20kit%20for%20high-performance%20e-commerce%20sites.&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&integration-ids=oac_MuWZiE4jtmQ2ejZQaQ7ncuDT) + +# Next.js Commerce + +The all-in-one starter kit for high-performance e-commerce sites. With a few clicks, Next.js developers can clone, deploy and fully customize their own store. +Start right now at [nextjs.org/commerce](https://nextjs.org/commerce) + +Demo live at: [demo.vercel.store](https://demo.vercel.store/) + +- Shopify Demo: https://shopify.vercel.store/ +- Swell Demo: https://swell.vercel.store/ +- BigCommerce Demo: https://bigcommerce.vercel.store/ +- Vendure Demo: https://vendure.vercel.store + +## Features + +- Performant by default +- SEO Ready +- Internationalization +- Responsive +- UI Components +- Theming +- Standardized Data Hooks +- Integrations - Integrate seamlessly with the most common ecommerce platforms. +- Dark Mode Support + +## Integrations + +Next.js Commerce integrates out-of-the-box with BigCommerce and Shopify. We plan to support all major ecommerce backends. + +## Considerations + +- `framework/commerce` contains all types, helpers and functions to be used as base to build a new **provider**. +- **Providers** live under `framework`'s root folder and they will extend Next.js Commerce types and functionality (`framework/commerce`). +- We have a **Features API** to ensure feature parity between the UI and the Provider. The UI should update accordingly and no extra code should be bundled. All extra configuration for features will live under `features` in `commerce.config.json` and if needed it can also be accessed programatically. +- Each **provider** should add its corresponding `next.config.js` and `commerce.config.json` adding specific data related to the provider. For example in case of BigCommerce, the images CDN and additional API routes. +- **Providers don't depend on anything that's specific to the application they're used in**. They only depend on `framework/commerce`, on their own framework folder and on some dependencies included in `package.json` + +## Configuration + +### How to change providers + +Open `.env.local` and change the value of `COMMERCE_PROVIDER` to the provider you would like to use, then set the environment variables for that provider (use `.env.template` as the base). + +The setup for Shopify would look like this for example: + +``` +COMMERCE_PROVIDER=shopify +NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxx +NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN=xxxxxxx.myshopify.com +``` + +And change the `tsconfig.json` to resolve to the chosen provider: + +``` + "@framework": ["framework/shopify"], + "@framework/*": ["framework/shopify/*"] +``` + +That's it! + +### Features + +Every provider defines the features that it supports under `framework/{provider}/commerce.config.json` + +#### How to turn Features on and off + +> NOTE: The selected provider should support the feature that you are toggling. (This means that you can't turn wishlist on if the provider doesn't support this functionality out the box) + +- Open `commerce.config.json` +- You'll see a config file like this: + ```json + { + "features": { + "wishlist": false + } + } + ``` +- Turn wishlist on by setting wishlist to true. +- Run the app and the wishlist functionality should be back on. + +### How to create a new provider + +Follow our docs for [Adding a new Commerce Provider](framework/commerce/new-provider.md). + +If you succeeded building a provider, submit a PR with a valid demo and we'll review it asap. + +## Contribute + +Our commitment to Open Source can be found [here](https://vercel.com/oss). + +1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device. +2. Create a new branch `git checkout -b MY_BRANCH_NAME` +3. Install yarn: `npm install -g yarn` +4. Install the dependencies: `yarn` +5. Duplicate `.env.template` and rename it to `.env.local` +6. Add proper store values to `.env.local` +7. Run `yarn dev` to build and watch for code changes + +## Work in progress + +We're using Github Projects to keep track of issues in progress and todo's. Here is our [Board](https://github.com/vercel/commerce/projects/1) + +People actively working on this project: @okbel & @lfades. + +## Troubleshoot + +
+I already own a BigCommerce store. What should I do? +
+First thing you do is: set your environment variables +
+
+.env.local + +```sh +BIGCOMMERCE_STOREFRONT_API_URL=<> +BIGCOMMERCE_STOREFRONT_API_TOKEN=<> +BIGCOMMERCE_STORE_API_URL=<> +BIGCOMMERCE_STORE_API_TOKEN=<> +BIGCOMMERCE_STORE_API_CLIENT_ID=<> +BIGCOMMERCE_CHANNEL_ID=<> +``` + +If your project was started with a "Deploy with Vercel" button, you can use Vercel's CLI to retrieve these credentials. + +1. Install Vercel CLI: `npm i -g vercel` +2. Link local instance with Vercel and Github accounts (creates .vercel file): `vercel link` +3. Download your environment variables: `vercel env pull .env.local` + +Next, you're free to customize the starter. More updates coming soon. Stay tuned. + +
+ +
+BigCommerce shows a Coming Soon page and requests a Preview Code +
+After Email confirmation, Checkout should be manually enabled through BigCommerce platform. Look for "Review & test your store" section through BigCommerce's dashboard. +
+
+BigCommerce team has been notified and they plan to add more detailed about this subject. +
diff --git a/assets/base.css b/assets/base.css new file mode 100644 index 00000000..e63ea1aa --- /dev/null +++ b/assets/base.css @@ -0,0 +1,129 @@ +:root { + --primary: #ffffff; + --primary-2: #f1f3f5; + --secondary: #000000; + --secondary-2: #111; + --selection: var(--cyan); + + --text-base: #000000; + --text-primary: #000000; + --text-secondary: white; + + --hover: rgba(0, 0, 0, 0.075); + --hover-1: rgba(0, 0, 0, 0.15); + --hover-2: rgba(0, 0, 0, 0.25); + --cyan: #22b8cf; + --green: #37b679; + --red: #da3c3c; + --pink: #e64980; + --purple: #f81ce5; + --blue: #0070f3; + --violet: #5f3dc4; + --violet-light: #7048e8; + --accents-0: #f8f9fa; + --accents-1: #f1f3f5; + --accents-2: #e9ecef; + --accents-3: #dee2e6; + --accents-4: #ced4da; + --accents-5: #adb5bd; + --accents-6: #868e96; + --accents-7: #495057; + --accents-8: #343a40; + --accents-9: #212529; + --font-sans: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue', + 'Helvetica', sans-serif; +} + +[data-theme='dark'] { + --primary: #000000; + --primary-2: #111; + --secondary: #ffffff; + --secondary-2: #f1f3f5; + --hover: rgba(255, 255, 255, 0.075); + --hover-1: rgba(255, 255, 255, 0.15); + --hover-2: rgba(255, 255, 255, 0.25); + --selection: var(--purple); + + --text-base: white; + --text-primary: white; + --text-secondary: black; + + --accents-0: #212529; + --accents-1: #343a40; + --accents-2: #495057; + --accents-3: #868e96; + --accents-4: #adb5bd; + --accents-5: #ced4da; + --accents-6: #dee2e6; + --accents-7: #e9ecef; + --accents-8: #f1f3f5; + --accents-9: #f8f9fa; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +html { + height: 100%; + box-sizing: border-box; + touch-action: manipulation; + font-feature-settings: 'case' 1, 'rlig' 1, 'calt' 0; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +html, +body { + font-family: var(--font-sans); + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background-color: var(--primary); + color: var(--text-primary); +} + +body { + position: relative; + min-height: 100%; + margin: 0; +} + +a { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.animated { + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} + +.fadeIn { + -webkit-animation-name: fadeIn; + animation-name: fadeIn; +} + +@-webkit-keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} diff --git a/assets/chrome-bug.css b/assets/chrome-bug.css new file mode 100644 index 00000000..245ec8f0 --- /dev/null +++ b/assets/chrome-bug.css @@ -0,0 +1,12 @@ +/** + * Chrome has a bug with transitions on load since 2012! + * + * To prevent a "pop" of content, you have to disable all transitions until + * the page is done loading. + * + * https://lab.laukstein.com/bug/input + * https://twitter.com/timer150/status/1345217126680899584 + */ +body.loading * { + transition: none !important; +} diff --git a/assets/components.css b/assets/components.css new file mode 100644 index 00000000..ebebcc23 --- /dev/null +++ b/assets/components.css @@ -0,0 +1,3 @@ +.fit { + min-height: calc(100vh - 88px); +} diff --git a/assets/main.css b/assets/main.css new file mode 100644 index 00000000..54dd1e50 --- /dev/null +++ b/assets/main.css @@ -0,0 +1,7 @@ +@tailwind base; +@import './base.css'; + +@tailwind components; +@import './components.css'; + +@tailwind utilities; diff --git a/codegen.json b/codegen.json new file mode 100644 index 00000000..1f14e88a --- /dev/null +++ b/codegen.json @@ -0,0 +1,27 @@ +{ + "schema": { + "https://buybutton.store/graphql": { + "headers": { + "Authorization": "Bearer xzy" + } + } + }, + "documents": [ + { + "./framework/bigcommerce/api/**/*.ts": { + "noRequire": true + } + } + ], + "generates": { + "./framework/bigcommerce/schema.d.ts": { + "plugins": ["typescript", "typescript-operations"] + }, + "./framework/bigcommerce/schema.graphql": { + "plugins": ["schema-ast"] + } + }, + "hooks": { + "afterAllFileWrite": ["prettier --write"] + } +} diff --git a/commerce.config.json b/commerce.config.json new file mode 100644 index 00000000..ce78b1b1 --- /dev/null +++ b/commerce.config.json @@ -0,0 +1,7 @@ +{ + "provider": "reactioncommerce", + "features": { + "wishlist": false, + "customCheckout": true + } +} diff --git a/components/auth/ForgotPassword.tsx b/components/auth/ForgotPassword.tsx new file mode 100644 index 00000000..597ee328 --- /dev/null +++ b/components/auth/ForgotPassword.tsx @@ -0,0 +1,78 @@ +import { FC, useEffect, useState, useCallback } from 'react' +import { validate } from 'email-validator' +import { useUI } from '@components/ui/context' +import { Logo, Button, Input } from '@components/ui' + +interface Props {} + +const ForgotPassword: FC = () => { + // Form State + const [email, setEmail] = useState('') + const [loading, setLoading] = useState(false) + const [message, setMessage] = useState('') + const [dirty, setDirty] = useState(false) + const [disabled, setDisabled] = useState(false) + + const { setModalView, closeModal } = useUI() + + const handleResetPassword = async (e: React.SyntheticEvent) => { + e.preventDefault() + + if (!dirty && !disabled) { + setDirty(true) + handleValidation() + } + } + + const handleValidation = useCallback(() => { + // Unable to send form unless fields are valid. + if (dirty) { + setDisabled(!validate(email)) + } + }, [email, dirty]) + + useEffect(() => { + handleValidation() + }, [handleValidation]) + + return ( +
+
+ +
+
+ {message && ( +
{message}
+ )} + + +
+ +
+ + + Do you have an account? + {` `} + setModalView('LOGIN_VIEW')} + > + Log In + + +
+
+ ) +} + +export default ForgotPassword diff --git a/components/auth/LoginView.tsx b/components/auth/LoginView.tsx new file mode 100644 index 00000000..89d5bf89 --- /dev/null +++ b/components/auth/LoginView.tsx @@ -0,0 +1,104 @@ +import { FC, useEffect, useState, useCallback } from 'react' +import { Logo, Button, Input } from '@components/ui' +import useLogin from '@framework/auth/use-login' +import { useUI } from '@components/ui/context' +import { validate } from 'email-validator' + +interface Props {} + +const LoginView: FC = () => { + // Form State + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [loading, setLoading] = useState(false) + const [message, setMessage] = useState('') + const [dirty, setDirty] = useState(false) + const [disabled, setDisabled] = useState(false) + const { setModalView, closeModal } = useUI() + + const login = useLogin() + + const handleLogin = async (e: React.SyntheticEvent) => { + e.preventDefault() + + if (!dirty && !disabled) { + setDirty(true) + handleValidation() + } + + try { + setLoading(true) + setMessage('') + await login({ + email, + password, + }) + setLoading(false) + closeModal() + } catch ({ errors }) { + setMessage(errors[0].message) + setLoading(false) + } + } + + const handleValidation = useCallback(() => { + // Test for Alphanumeric password + const validPassword = /^(?=.*[a-zA-Z])(?=.*[0-9])/.test(password) + + // Unable to send form unless fields are valid. + if (dirty) { + setDisabled(!validate(email) || password.length < 7 || !validPassword) + } + }, [email, password, dirty]) + + useEffect(() => { + handleValidation() + }, [handleValidation]) + + return ( +
+
+ +
+
+ {message && ( + + )} + + + + +
+ Don't have an account? + {` `} + setModalView('SIGNUP_VIEW')} + > + Sign Up + +
+
+
+ ) +} + +export default LoginView diff --git a/components/auth/SignUpView.tsx b/components/auth/SignUpView.tsx new file mode 100644 index 00000000..1b619828 --- /dev/null +++ b/components/auth/SignUpView.tsx @@ -0,0 +1,114 @@ +import { FC, useEffect, useState, useCallback } from 'react' +import { validate } from 'email-validator' +import { Info } from '@components/icons' +import { useUI } from '@components/ui/context' +import { Logo, Button, Input } from '@components/ui' +import useSignup from '@framework/auth/use-signup' + +interface Props {} + +const SignUpView: FC = () => { + // Form State + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [firstName, setFirstName] = useState('') + const [lastName, setLastName] = useState('') + const [loading, setLoading] = useState(false) + const [message, setMessage] = useState('') + const [dirty, setDirty] = useState(false) + const [disabled, setDisabled] = useState(false) + + const signup = useSignup() + const { setModalView, closeModal } = useUI() + + const handleSignup = async (e: React.SyntheticEvent) => { + e.preventDefault() + + if (!dirty && !disabled) { + setDirty(true) + handleValidation() + } + + try { + setLoading(true) + setMessage('') + await signup({ + email, + firstName, + lastName, + password, + }) + setLoading(false) + closeModal() + } catch ({ errors }) { + setMessage(errors[0].message) + setLoading(false) + } + } + + const handleValidation = useCallback(() => { + // Test for Alphanumeric password + const validPassword = /^(?=.*[a-zA-Z])(?=.*[0-9])/.test(password) + + // Unable to send form unless fields are valid. + if (dirty) { + setDisabled(!validate(email) || password.length < 7 || !validPassword) + } + }, [email, password, dirty]) + + useEffect(() => { + handleValidation() + }, [handleValidation]) + + return ( +
+
+ +
+
+ {message && ( +
{message}
+ )} + + + + + + + + {' '} + + Info: Passwords must be longer than 7 chars and + include numbers.{' '} + + +
+ +
+ + + Do you have an account? + {` `} + setModalView('LOGIN_VIEW')} + > + Log In + + +
+
+ ) +} + +export default SignUpView diff --git a/components/auth/index.ts b/components/auth/index.ts new file mode 100644 index 00000000..11571fac --- /dev/null +++ b/components/auth/index.ts @@ -0,0 +1,3 @@ +export { default as LoginView } from './LoginView' +export { default as SignUpView } from './SignUpView' +export { default as ForgotPassword } from './ForgotPassword' diff --git a/components/cart/CartItem/CartItem.module.css b/components/cart/CartItem/CartItem.module.css new file mode 100644 index 00000000..70d29fc0 --- /dev/null +++ b/components/cart/CartItem/CartItem.module.css @@ -0,0 +1,18 @@ +.quantity { + appearance: textfield; + @apply w-8 border-accents-2 border mx-3 rounded text-center text-sm text-black; +} + +.quantity::-webkit-outer-spin-button, +.quantity::-webkit-inner-spin-button { + @apply appearance-none m-0; +} + +.productImage { + position: absolute; + transform: scale(1.9); + width: 100%; + height: 100%; + left: 30% !important; + top: 30% !important; +} diff --git a/components/cart/CartItem/CartItem.tsx b/components/cart/CartItem/CartItem.tsx new file mode 100644 index 00000000..8bb5201c --- /dev/null +++ b/components/cart/CartItem/CartItem.tsx @@ -0,0 +1,164 @@ +import { ChangeEvent, useEffect, useState } from 'react' +import cn from 'classnames' +import Image from 'next/image' +import Link from 'next/link' +import s from './CartItem.module.css' +import { Trash, Plus, Minus } from '@components/icons' +import { useUI } from '@components/ui/context' +import type { LineItem } from '@framework/types' +import usePrice from '@framework/product/use-price' +import useUpdateItem from '@framework/cart/use-update-item' +import useRemoveItem from '@framework/cart/use-remove-item' + +type ItemOption = { + name: string + nameId: number + value: string + valueId: number +} + +const CartItem = ({ + item, + currencyCode, + ...rest +}: { + item: LineItem + currencyCode: string +}) => { + const { closeSidebarIfPresent } = useUI() + + const { price } = usePrice({ + amount: item.variant.price * item.quantity, + baseAmount: item.variant.listPrice * item.quantity, + currencyCode, + }) + + const updateItem = useUpdateItem({ item }) + const removeItem = useRemoveItem() + const [quantity, setQuantity] = useState(item.quantity) + const [removing, setRemoving] = useState(false) + + const updateQuantity = async (val: number) => { + console.log('updateQuantity', val) + await updateItem({ quantity: val }) + } + + const handleQuantity = (e: ChangeEvent) => { + const val = Number(e.target.value) + + if (Number.isInteger(val) && val >= 0) { + setQuantity(Number(e.target.value)) + } + } + const handleBlur = () => { + const val = Number(quantity) + + if (val !== item.quantity) { + updateQuantity(val) + } + } + const increaseQuantity = (n = 1) => { + const val = Number(quantity) + n + + if (Number.isInteger(val) && val >= 0) { + setQuantity(val) + updateQuantity(val) + } + } + const handleRemove = async () => { + setRemoving(true) + + try { + // If this action succeeds then there's no need to do `setRemoving(true)` + // because the component will be removed from the view + await removeItem(item) + } catch (error) { + setRemoving(false) + } + } + // TODO: Add a type for this + const options = (item as any).options + + useEffect(() => { + // Reset the quantity state if the item quantity changes + if (item.quantity !== Number(quantity)) { + setQuantity(item.quantity) + } + }, [item.quantity]) + + return ( +
  • +
    + + closeSidebarIfPresent()} + className={s.productImage} + width={150} + height={150} + src={item.variant.image!.url} + alt={item.variant.image!.altText} + unoptimized + /> + +
    +
    + + closeSidebarIfPresent()} + > + {item.name} + + + {options && options.length > 0 ? ( +
    + {options.map((option: ItemOption, i: number) => ( + + {option.value} + {i === options.length - 1 ? '' : ', '} + + ))} +
    + ) : null} +
    + + + +
    +
    +
    + {price} + +
    +
  • + ) +} + +export default CartItem diff --git a/components/cart/CartItem/index.ts b/components/cart/CartItem/index.ts new file mode 100644 index 00000000..b5f6dc52 --- /dev/null +++ b/components/cart/CartItem/index.ts @@ -0,0 +1 @@ +export { default } from './CartItem' diff --git a/components/cart/CartSidebarView/CartSidebarView.module.css b/components/cart/CartSidebarView/CartSidebarView.module.css new file mode 100644 index 00000000..9b94021a --- /dev/null +++ b/components/cart/CartSidebarView/CartSidebarView.module.css @@ -0,0 +1,15 @@ +.root { + @apply h-full flex flex-col; +} + +.root.empty { + @apply bg-secondary text-secondary; +} + +.root.success { + @apply bg-green text-white; +} + +.root.error { + @apply bg-red text-white; +} diff --git a/components/cart/CartSidebarView/CartSidebarView.tsx b/components/cart/CartSidebarView/CartSidebarView.tsx new file mode 100644 index 00000000..32639032 --- /dev/null +++ b/components/cart/CartSidebarView/CartSidebarView.tsx @@ -0,0 +1,141 @@ +import { FC } from 'react' +import cn from 'classnames' +import Link from 'next/link' +import CartItem from '../CartItem' +import s from './CartSidebarView.module.css' +import { Button } from '@components/ui' +import { UserNav } from '@components/common' +import { useUI } from '@components/ui/context' +import { Bag, Cross, Check } from '@components/icons' +import useCart from '@framework/cart/use-cart' +import usePrice from '@framework/product/use-price' + +const CartSidebarView: FC = () => { + const { closeSidebar } = useUI() + const { data, isLoading, isEmpty } = useCart() + + const { price: subTotal } = usePrice( + data && { + amount: Number(data.subtotalPrice), + currencyCode: data.currency.code, + } + ) + const { price: total } = usePrice( + data && { + amount: Number(data.totalPrice), + currencyCode: data.currency.code, + } + ) + const handleClose = () => closeSidebar() + + const error = null + const success = null + + return ( +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + + {isLoading || isEmpty ? ( +
    + + + +

    + Your cart is empty +

    +

    + Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake. +

    +
    + ) : error ? ( +
    + + + +

    + We couldn’t process the purchase. Please check your card information + and try again. +

    +
    + ) : success ? ( +
    + + + +

    + Thank you for your order. +

    +
    + ) : ( + <> +
    + +

    + My Cart +

    + +
      + {data!.lineItems.map((item: any) => ( + + ))} +
    +
    + +
    +
    +
      +
    • + Subtotal + {subTotal} +
    • +
    • + Taxes + Calculated at checkout +
    • +
    • + Estimated Shipping + FREE +
    • +
    +
    + Total + {total} +
    +
    + +
    + + )} +
    + ) +} + +export default CartSidebarView diff --git a/components/cart/CartSidebarView/index.ts b/components/cart/CartSidebarView/index.ts new file mode 100644 index 00000000..0262e448 --- /dev/null +++ b/components/cart/CartSidebarView/index.ts @@ -0,0 +1 @@ +export { default } from './CartSidebarView' diff --git a/components/cart/index.ts b/components/cart/index.ts new file mode 100644 index 00000000..3e53fa34 --- /dev/null +++ b/components/cart/index.ts @@ -0,0 +1,2 @@ +export { default as CartSidebarView } from './CartSidebarView' +export { default as CartItem } from './CartItem' diff --git a/components/common/Avatar/Avatar.tsx b/components/common/Avatar/Avatar.tsx new file mode 100644 index 00000000..f78aa1d0 --- /dev/null +++ b/components/common/Avatar/Avatar.tsx @@ -0,0 +1,24 @@ +import { FC, useRef, useEffect } from 'react' +import { useUserAvatar } from '@lib/hooks/useUserAvatar' + +interface Props { + className?: string + children?: any +} + +const Avatar: FC = ({}) => { + let ref = useRef() as React.MutableRefObject + let { userAvatar } = useUserAvatar() + + return ( +
    + {/* Add an image - We're generating a gradient as placeholder */} +
    + ) +} + +export default Avatar diff --git a/components/common/Avatar/index.ts b/components/common/Avatar/index.ts new file mode 100644 index 00000000..a4600ec7 --- /dev/null +++ b/components/common/Avatar/index.ts @@ -0,0 +1 @@ +export { default } from './Avatar' diff --git a/components/common/FeatureBar/FeatureBar.module.css b/components/common/FeatureBar/FeatureBar.module.css new file mode 100644 index 00000000..419fd4b0 --- /dev/null +++ b/components/common/FeatureBar/FeatureBar.module.css @@ -0,0 +1,9 @@ +.root { + @apply text-center p-6 bg-primary text-sm flex-row justify-center items-center font-medium fixed bottom-0 w-full z-30 transition-all duration-300 ease-out; +} + +@screen md { + .root { + @apply flex text-left; + } +} diff --git a/components/common/FeatureBar/FeatureBar.tsx b/components/common/FeatureBar/FeatureBar.tsx new file mode 100644 index 00000000..8923a721 --- /dev/null +++ b/components/common/FeatureBar/FeatureBar.tsx @@ -0,0 +1,39 @@ +import cn from 'classnames' +import s from './FeatureBar.module.css' + +interface FeatureBarProps { + className?: string + title: string + description?: string + hide?: boolean + action?: React.ReactNode +} + +const FeatureBar: React.FC = ({ + title, + description, + className, + action, + hide, +}) => { + const rootClassName = cn( + s.root, + { + transform: true, + 'translate-y-0 opacity-100': !hide, + 'translate-y-full opacity-0': hide, + }, + className + ) + return ( +
    + {title} + + {description} + + {action && action} +
    + ) +} + +export default FeatureBar diff --git a/components/common/FeatureBar/index.ts b/components/common/FeatureBar/index.ts new file mode 100644 index 00000000..d78bc9d2 --- /dev/null +++ b/components/common/FeatureBar/index.ts @@ -0,0 +1 @@ +export { default } from './FeatureBar' diff --git a/components/common/Footer/Footer.module.css b/components/common/Footer/Footer.module.css new file mode 100644 index 00000000..259318ec --- /dev/null +++ b/components/common/Footer/Footer.module.css @@ -0,0 +1,9 @@ +.link { + & > svg { + @apply transform duration-75 ease-linear; + } + + &:hover > svg { + @apply scale-110; + } +} diff --git a/components/common/Footer/Footer.tsx b/components/common/Footer/Footer.tsx new file mode 100644 index 00000000..5fb9ede5 --- /dev/null +++ b/components/common/Footer/Footer.tsx @@ -0,0 +1,145 @@ +import { FC } from 'react' +import cn from 'classnames' +import Link from 'next/link' +import { useRouter } from 'next/router' +import type { Page } from '@framework/common/get-all-pages' +import getSlug from '@lib/get-slug' +import { Github, Vercel } from '@components/icons' +import { Logo, Container } from '@components/ui' +import { I18nWidget } from '@components/common' +import s from './Footer.module.css' + +interface Props { + className?: string + children?: any + pages?: Page[] +} + +const LEGAL_PAGES = ['terms-of-use', 'shipping-returns', 'privacy-policy'] + +const Footer: FC = ({ className, pages }) => { + const { sitePages, legalPages } = usePages(pages) + const rootClassName = cn(className) + + return ( + + ) +} + +function usePages(pages?: Page[]) { + const { locale } = useRouter() + const sitePages: Page[] = [] + const legalPages: Page[] = [] + + if (pages) { + pages.forEach((page) => { + const slug = page.url && getSlug(page.url) + + if (!slug) return + if (locale && !slug.startsWith(`${locale}/`)) return + + if (isLegalPage(slug, locale)) { + legalPages.push(page) + } else { + sitePages.push(page) + } + }) + } + + return { + sitePages: sitePages.sort(bySortOrder), + legalPages: legalPages.sort(bySortOrder), + } +} + +const isLegalPage = (slug: string, locale?: string) => + locale + ? LEGAL_PAGES.some((p) => `${locale}/${p}` === slug) + : LEGAL_PAGES.includes(slug) + +// Sort pages by the sort order assigned in the BC dashboard +function bySortOrder(a: Page, b: Page) { + return (a.sort_order ?? 0) - (b.sort_order ?? 0) +} + +export default Footer diff --git a/components/common/Footer/index.ts b/components/common/Footer/index.ts new file mode 100644 index 00000000..5d06e9b7 --- /dev/null +++ b/components/common/Footer/index.ts @@ -0,0 +1 @@ +export { default } from './Footer' diff --git a/components/common/Head/Head.tsx b/components/common/Head/Head.tsx new file mode 100644 index 00000000..b2c0c997 --- /dev/null +++ b/components/common/Head/Head.tsx @@ -0,0 +1,18 @@ +import { FC } from 'react' +import NextHead from 'next/head' +import { DefaultSeo } from 'next-seo' +import config from '@config/seo.json' + +const Head: FC = () => { + return ( + <> + + + + + + + ) +} + +export default Head diff --git a/components/common/Head/index.ts b/components/common/Head/index.ts new file mode 100644 index 00000000..b317a124 --- /dev/null +++ b/components/common/Head/index.ts @@ -0,0 +1 @@ +export { default } from './Head' diff --git a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.module.css b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.module.css new file mode 100644 index 00000000..ec2f8ea4 --- /dev/null +++ b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.module.css @@ -0,0 +1,23 @@ +.root { + @apply py-12 flex flex-col w-full px-6; + + @screen md { + @apply flex-row; + } + + & .asideWrapper { + @apply pr-3 w-full relative; + + @screen md { + @apply w-48; + } + } + + & .aside { + @apply flex flex-row w-full justify-around mb-12; + + @screen md { + @apply mb-0 block sticky top-32; + } + } +} diff --git a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx new file mode 100644 index 00000000..423048f7 --- /dev/null +++ b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx @@ -0,0 +1,73 @@ +import { FC } from 'react' +import Link from 'next/link' +import type { Product } from '@commerce/types' +import { Grid } from '@components/ui' +import { ProductCard } from '@components/product' +import s from './HomeAllProductsGrid.module.css' +import { getCategoryPath, getDesignerPath } from '@lib/search' + +interface Props { + categories?: any + brands?: any + products?: Product[] +} + +const HomeAllProductsGrid: FC = ({ + categories, + brands, + products = [], +}) => { + return ( +
    +
    +
    + + +
    +
    +
    + + {products.map((product) => ( + + ))} + +
    +
    + ) +} + +export default HomeAllProductsGrid diff --git a/components/common/HomeAllProductsGrid/index.ts b/components/common/HomeAllProductsGrid/index.ts new file mode 100644 index 00000000..31d313d1 --- /dev/null +++ b/components/common/HomeAllProductsGrid/index.ts @@ -0,0 +1 @@ +export { default } from './HomeAllProductsGrid' diff --git a/components/common/I18nWidget/I18nWidget.module.css b/components/common/I18nWidget/I18nWidget.module.css new file mode 100644 index 00000000..f100fd47 --- /dev/null +++ b/components/common/I18nWidget/I18nWidget.module.css @@ -0,0 +1,44 @@ +.root { + @apply relative; +} + +.button { + @apply h-10 px-2 rounded-md border border-accents-2 flex items-center justify-center; +} + +.button:hover { + @apply border-accents-4 shadow-sm; +} + +.button:focus { + @apply outline-none; +} + +.dropdownMenu { + @apply fixed right-0 top-12 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full; +} + +@screen lg { + .dropdownMenu { + @apply absolute border border-accents-1 shadow-lg w-56 h-auto; + } +} + +@screen md { + .closeButton { + @apply hidden; + } +} + +.item { + @apply flex cursor-pointer px-6 py-3 transition ease-in-out duration-150 text-primary leading-6 font-medium items-center; + text-transform: capitalize; +} + +.item:hover { + @apply bg-accents-1; +} + +.icon { + transform: rotate(180deg); +} diff --git a/components/common/I18nWidget/I18nWidget.tsx b/components/common/I18nWidget/I18nWidget.tsx new file mode 100644 index 00000000..fbe67a4c --- /dev/null +++ b/components/common/I18nWidget/I18nWidget.tsx @@ -0,0 +1,101 @@ +import cn from 'classnames' +import Link from 'next/link' +import { FC, useState } from 'react' +import { useRouter } from 'next/router' +import s from './I18nWidget.module.css' +import { Cross, ChevronUp } from '@components/icons' +import ClickOutside from '@lib/click-outside' +interface LOCALE_DATA { + name: string + img: { + filename: string + alt: string + } +} + +const LOCALES_MAP: Record = { + es: { + name: 'Español', + img: { + filename: 'flag-es-co.svg', + alt: 'Bandera Colombiana', + }, + }, + 'en-US': { + name: 'English', + img: { + filename: 'flag-en-us.svg', + alt: 'US Flag', + }, + }, +} + +const I18nWidget: FC = () => { + const [display, setDisplay] = useState(false) + const { + locale, + locales, + defaultLocale = 'en-US', + asPath: currentPath, + } = useRouter() + + const options = locales?.filter((val) => val !== locale) + const currentLocale = locale || defaultLocale + + return ( + setDisplay(false)}> + + + ) +} + +export default I18nWidget diff --git a/components/common/I18nWidget/index.ts b/components/common/I18nWidget/index.ts new file mode 100644 index 00000000..46525c3d --- /dev/null +++ b/components/common/I18nWidget/index.ts @@ -0,0 +1 @@ +export { default } from './I18nWidget' diff --git a/components/common/Layout/Layout.module.css b/components/common/Layout/Layout.module.css new file mode 100644 index 00000000..bb90675a --- /dev/null +++ b/components/common/Layout/Layout.module.css @@ -0,0 +1,4 @@ +.root { + @apply h-full bg-primary mx-auto transition-colors duration-150; + max-width: 2460px; +} diff --git a/components/common/Layout/Layout.tsx b/components/common/Layout/Layout.tsx new file mode 100644 index 00000000..54749c46 --- /dev/null +++ b/components/common/Layout/Layout.tsx @@ -0,0 +1,92 @@ +import cn from 'classnames' +import dynamic from 'next/dynamic' +import s from './Layout.module.css' +import { useRouter } from 'next/router' +import React, { FC } from 'react' +import { useUI } from '@components/ui/context' +import { Navbar, Footer } from '@components/common' +import { useAcceptCookies } from '@lib/hooks/useAcceptCookies' +import { Sidebar, Button, Modal, LoadingDots } from '@components/ui' +import CartSidebarView from '@components/cart/CartSidebarView' + +import LoginView from '@components/auth/LoginView' +import { CommerceProvider } from '@framework' +import type { Page } from '@framework/common/get-all-pages' + +const Loading = () => ( +
    + +
    +) + +const dynamicProps = { + loading: () => , +} + +const SignUpView = dynamic( + () => import('@components/auth/SignUpView'), + dynamicProps +) + +const ForgotPassword = dynamic( + () => import('@components/auth/ForgotPassword'), + dynamicProps +) + +const FeatureBar = dynamic( + () => import('@components/common/FeatureBar'), + dynamicProps +) + +interface Props { + pageProps: { + pages?: Page[] + commerceFeatures: Record + } +} + +const Layout: FC = ({ + children, + pageProps: { commerceFeatures, ...pageProps }, +}) => { + const { + displaySidebar, + displayModal, + closeSidebar, + closeModal, + modalView, + } = useUI() + const { acceptedCookies, onAcceptCookies } = useAcceptCookies() + const { locale = 'en-US' } = useRouter() + return ( + +
    + +
    {children}
    +
    + + + {modalView === 'LOGIN_VIEW' && } + {modalView === 'SIGNUP_VIEW' && } + {modalView === 'FORGOT_VIEW' && } + + + + + + + onAcceptCookies()}> + Accept cookies + + } + /> +
    +
    + ) +} + +export default Layout diff --git a/components/common/Layout/index.ts b/components/common/Layout/index.ts new file mode 100644 index 00000000..0e2737ee --- /dev/null +++ b/components/common/Layout/index.ts @@ -0,0 +1 @@ +export { default } from './Layout' diff --git a/components/common/Navbar/Navbar.module.css b/components/common/Navbar/Navbar.module.css new file mode 100644 index 00000000..753bdbf1 --- /dev/null +++ b/components/common/Navbar/Navbar.module.css @@ -0,0 +1,24 @@ +.root { + @apply sticky top-0 bg-primary z-40 transition-all duration-150; +} + +.link { + @apply inline-flex items-center text-primary leading-6 font-medium transition ease-in-out duration-75 cursor-pointer text-accents-6; +} + +.link:hover { + @apply text-accents-9; +} + +.link:focus { + @apply outline-none text-accents-8; +} + +.logo { + @apply cursor-pointer rounded-full border transform duration-100 ease-in-out; + + &:hover { + @apply shadow-md; + transform: scale(1.05); + } +} diff --git a/components/common/Navbar/Navbar.tsx b/components/common/Navbar/Navbar.tsx new file mode 100644 index 00000000..fcf9f1e1 --- /dev/null +++ b/components/common/Navbar/Navbar.tsx @@ -0,0 +1,50 @@ +import { FC } from 'react' +import Link from 'next/link' +import { Logo, Container } from '@components/ui' +import { Searchbar, UserNav } from '@components/common' +import NavbarRoot from './NavbarRoot' +import s from './Navbar.module.css' + +const Navbar: FC = () => ( + + +
    +
    + + + + + + +
    + +
    + +
    + +
    + +
    +
    + +
    + +
    +
    +
    +) + +export default Navbar diff --git a/components/common/Navbar/NavbarRoot.tsx b/components/common/Navbar/NavbarRoot.tsx new file mode 100644 index 00000000..2eb8c542 --- /dev/null +++ b/components/common/Navbar/NavbarRoot.tsx @@ -0,0 +1,33 @@ +import { FC, useState, useEffect } from 'react' +import throttle from 'lodash.throttle' +import cn from 'classnames' +import s from './Navbar.module.css' + +const NavbarRoot: FC = ({ children }) => { + const [hasScrolled, setHasScrolled] = useState(false) + + useEffect(() => { + const handleScroll = throttle(() => { + const offset = 0 + const { scrollTop } = document.documentElement + const scrolled = scrollTop > offset + + if (hasScrolled !== scrolled) { + setHasScrolled(scrolled) + } + }, 200) + + document.addEventListener('scroll', handleScroll) + return () => { + document.removeEventListener('scroll', handleScroll) + } + }, [hasScrolled]) + + return ( +
    + {children} +
    + ) +} + +export default NavbarRoot diff --git a/components/common/Navbar/index.ts b/components/common/Navbar/index.ts new file mode 100644 index 00000000..e6400ae4 --- /dev/null +++ b/components/common/Navbar/index.ts @@ -0,0 +1 @@ +export { default } from './Navbar' diff --git a/components/common/Searchbar/Searchbar.module.css b/components/common/Searchbar/Searchbar.module.css new file mode 100644 index 00000000..071a14ef --- /dev/null +++ b/components/common/Searchbar/Searchbar.module.css @@ -0,0 +1,19 @@ +.input { + @apply bg-transparent px-3 py-2 appearance-none w-full transition duration-150 ease-in-out pr-10; + + @screen sm { + min-width: 300px; + } +} + +.input:focus { + @apply outline-none shadow-outline-normal; +} + +.iconContainer { + @apply absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none; +} + +.icon { + @apply h-5 w-5; +} diff --git a/components/common/Searchbar/Searchbar.tsx b/components/common/Searchbar/Searchbar.tsx new file mode 100644 index 00000000..c091a5ef --- /dev/null +++ b/components/common/Searchbar/Searchbar.tsx @@ -0,0 +1,66 @@ +import { FC, useEffect, useMemo } from 'react' +import cn from 'classnames' +import s from './Searchbar.module.css' +import { useRouter } from 'next/router' + +interface Props { + className?: string + id?: string +} + +const Searchbar: FC = ({ className, id = 'search' }) => { + const router = useRouter() + + useEffect(() => { + router.prefetch('/search') + }, []) + + return useMemo( + () => ( +
    + + { + e.preventDefault() + + if (e.key === 'Enter') { + const q = e.currentTarget.value + + router.push( + { + pathname: `/search`, + query: q ? { q } : {}, + }, + undefined, + { shallow: true } + ) + } + }} + /> +
    + + + +
    +
    + ), + [] + ) +} + +export default Searchbar diff --git a/components/common/Searchbar/index.ts b/components/common/Searchbar/index.ts new file mode 100644 index 00000000..e6c0e36c --- /dev/null +++ b/components/common/Searchbar/index.ts @@ -0,0 +1 @@ +export { default } from './Searchbar' diff --git a/components/common/UserNav/DropdownMenu.module.css b/components/common/UserNav/DropdownMenu.module.css new file mode 100644 index 00000000..b2756e9d --- /dev/null +++ b/components/common/UserNav/DropdownMenu.module.css @@ -0,0 +1,26 @@ +.dropdownMenu { + @apply fixed right-0 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full; +} + +@screen lg { + .dropdownMenu { + @apply absolute top-10 border border-accents-1 shadow-lg w-56 h-auto; + } +} + +.link { + @apply text-primary flex cursor-pointer px-6 py-3 flex transition ease-in-out duration-150 leading-6 font-medium items-center; + text-transform: capitalize; +} + +.link:hover { + @apply bg-accents-1; +} + +.link.active { + @apply font-bold bg-accents-2; +} + +.off { + @apply hidden; +} diff --git a/components/common/UserNav/DropdownMenu.tsx b/components/common/UserNav/DropdownMenu.tsx new file mode 100644 index 00000000..43f84200 --- /dev/null +++ b/components/common/UserNav/DropdownMenu.tsx @@ -0,0 +1,125 @@ +import cn from 'classnames' +import Link from 'next/link' +import { FC, useRef, useState, useEffect } from 'react' +import { useTheme } from 'next-themes' +import { useRouter } from 'next/router' +import s from './DropdownMenu.module.css' +import { Avatar } from '@components/common' +import { Moon, Sun } from '@components/icons' +import { useUI } from '@components/ui/context' +import ClickOutside from '@lib/click-outside' +import useLogout from '@framework/auth/use-logout' + +import { + disableBodyScroll, + enableBodyScroll, + clearAllBodyScrollLocks, +} from 'body-scroll-lock' + +interface DropdownMenuProps { + open?: boolean +} + +const LINKS = [ + { + name: 'My Orders', + href: '/orders', + }, + { + name: 'My Profile', + href: '/profile', + }, + { + name: 'My Cart', + href: '/cart', + }, +] + +const DropdownMenu: FC = ({ open = false }) => { + const logout = useLogout() + const { pathname } = useRouter() + const { theme, setTheme } = useTheme() + const [display, setDisplay] = useState(false) + const { closeSidebarIfPresent } = useUI() + const ref = useRef() as React.MutableRefObject + + useEffect(() => { + if (ref.current) { + if (display) { + disableBodyScroll(ref.current) + } else { + enableBodyScroll(ref.current) + } + } + return () => { + clearAllBodyScrollLocks() + } + }, [display]) + + return ( + setDisplay(false)}> + + + ) +} + +export default DropdownMenu diff --git a/components/common/UserNav/UserNav.module.css b/components/common/UserNav/UserNav.module.css new file mode 100644 index 00000000..cd1a6ce1 --- /dev/null +++ b/components/common/UserNav/UserNav.module.css @@ -0,0 +1,40 @@ +.root { + @apply relative; +} + +.list { + @apply flex flex-row items-center justify-items-end h-full; +} + +.item { + @apply mr-6 cursor-pointer relative transition ease-in-out duration-100 flex items-center outline-none text-primary; + + &:hover { + @apply text-accents-6 transition scale-110 duration-100; + } + + &:last-child { + @apply mr-0; + } + + &:focus, + &:active { + @apply outline-none; + } +} + +.bagCount { + @apply border border-accents-1 bg-secondary text-secondary absolute rounded-full right-3 top-3 flex items-center justify-center font-bold text-xs; + padding-left: 2.5px; + padding-right: 2.5px; + min-width: 1.25rem; + min-height: 1.25rem; +} + +.avatarButton { + @apply inline-flex justify-center rounded-full; +} + +.avatarButton:focus { + @apply outline-none; +} diff --git a/components/common/UserNav/UserNav.tsx b/components/common/UserNav/UserNav.tsx new file mode 100644 index 00000000..4d00970a --- /dev/null +++ b/components/common/UserNav/UserNav.tsx @@ -0,0 +1,61 @@ +import { FC } from 'react' +import Link from 'next/link' +import cn from 'classnames' +import type { LineItem } from '@framework/types' +import useCart from '@framework/cart/use-cart' +import useCustomer from '@framework/customer/use-customer' +import { Avatar } from '@components/common' +import { Heart, Bag } from '@components/icons' +import { useUI } from '@components/ui/context' +import DropdownMenu from './DropdownMenu' +import s from './UserNav.module.css' + +interface Props { + className?: string +} + +const countItem = (count: number, item: LineItem) => count + item.quantity + +const UserNav: FC = ({ className }) => { + const { data } = useCart() + const { data: customer } = useCustomer() + const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI() + const itemsCount = data?.lineItems.reduce(countItem, 0) ?? 0 + + return ( + + ) +} + +export default UserNav diff --git a/components/common/UserNav/index.ts b/components/common/UserNav/index.ts new file mode 100644 index 00000000..9e35ac01 --- /dev/null +++ b/components/common/UserNav/index.ts @@ -0,0 +1 @@ +export { default } from './UserNav' diff --git a/components/common/index.ts b/components/common/index.ts new file mode 100644 index 00000000..98dd3394 --- /dev/null +++ b/components/common/index.ts @@ -0,0 +1,9 @@ +export { default as Avatar } from './Avatar' +export { default as FeatureBar } from './FeatureBar' +export { default as Footer } from './Footer' +export { default as Layout } from './Layout' +export { default as Navbar } from './Navbar' +export { default as Searchbar } from './Searchbar' +export { default as UserNav } from './UserNav' +export { default as Head } from './Head' +export { default as I18nWidget } from './I18nWidget' diff --git a/components/icons/ArrowLeft.tsx b/components/icons/ArrowLeft.tsx new file mode 100644 index 00000000..8cc1e129 --- /dev/null +++ b/components/icons/ArrowLeft.tsx @@ -0,0 +1,27 @@ +const ArrowLeft = ({ ...props }) => { + return ( + + + + + ) +} + +export default ArrowLeft diff --git a/components/icons/Bag.tsx b/components/icons/Bag.tsx new file mode 100644 index 00000000..de2cde0d --- /dev/null +++ b/components/icons/Bag.tsx @@ -0,0 +1,33 @@ +const Bag = ({ ...props }) => { + return ( + + + + + + ) +} + +export default Bag diff --git a/components/icons/Check.tsx b/components/icons/Check.tsx new file mode 100644 index 00000000..89c91a1e --- /dev/null +++ b/components/icons/Check.tsx @@ -0,0 +1,21 @@ +const Check = ({ ...props }) => { + return ( + + + + ) +} + +export default Check diff --git a/components/icons/ChevronUp.tsx b/components/icons/ChevronUp.tsx new file mode 100644 index 00000000..69b9959b --- /dev/null +++ b/components/icons/ChevronUp.tsx @@ -0,0 +1,20 @@ +const ChevronUp = ({ ...props }) => { + return ( + + + + ) +} + +export default ChevronUp diff --git a/components/icons/CreditCard.tsx b/components/icons/CreditCard.tsx new file mode 100644 index 00000000..85504d8b --- /dev/null +++ b/components/icons/CreditCard.tsx @@ -0,0 +1,20 @@ +const CreditCard = ({ ...props }) => { + return ( + + + + + ) +} + +export default CreditCard diff --git a/components/icons/Cross.tsx b/components/icons/Cross.tsx new file mode 100644 index 00000000..12e115ac --- /dev/null +++ b/components/icons/Cross.tsx @@ -0,0 +1,21 @@ +const Cross = ({ ...props }) => { + return ( + + + + + ) +} + +export default Cross diff --git a/components/icons/DoubleChevron.tsx b/components/icons/DoubleChevron.tsx new file mode 100644 index 00000000..198c3046 --- /dev/null +++ b/components/icons/DoubleChevron.tsx @@ -0,0 +1,22 @@ +const DoubleChevron = ({ ...props }) => { + return ( + + + + ) +} + +export default DoubleChevron diff --git a/components/icons/Github.tsx b/components/icons/Github.tsx new file mode 100644 index 00000000..1195a3c3 --- /dev/null +++ b/components/icons/Github.tsx @@ -0,0 +1,20 @@ +const Github = ({ ...props }) => { + return ( + + + + ) +} + +export default Github diff --git a/components/icons/Heart.tsx b/components/icons/Heart.tsx new file mode 100644 index 00000000..afa2f6aa --- /dev/null +++ b/components/icons/Heart.tsx @@ -0,0 +1,22 @@ +const Heart = ({ ...props }) => { + return ( + + + + ) +} + +export default Heart diff --git a/components/icons/Info.tsx b/components/icons/Info.tsx new file mode 100644 index 00000000..67c79cf2 --- /dev/null +++ b/components/icons/Info.tsx @@ -0,0 +1,22 @@ +const Info = ({ ...props }) => { + return ( + + + + + + ) +} + +export default Info diff --git a/components/icons/MapPin.tsx b/components/icons/MapPin.tsx new file mode 100644 index 00000000..6323b9c1 --- /dev/null +++ b/components/icons/MapPin.tsx @@ -0,0 +1,20 @@ +const MapPin = ({ ...props }) => { + return ( + + + + + ) +} + +export default MapPin diff --git a/components/icons/Minus.tsx b/components/icons/Minus.tsx new file mode 100644 index 00000000..1e9411dd --- /dev/null +++ b/components/icons/Minus.tsx @@ -0,0 +1,15 @@ +const Minus = ({ ...props }) => { + return ( + + + + ) +} + +export default Minus diff --git a/components/icons/Moon.tsx b/components/icons/Moon.tsx new file mode 100644 index 00000000..e02f2a30 --- /dev/null +++ b/components/icons/Moon.tsx @@ -0,0 +1,20 @@ +const Moon = ({ ...props }) => { + return ( + + + + ) +} + +export default Moon diff --git a/components/icons/Plus.tsx b/components/icons/Plus.tsx new file mode 100644 index 00000000..ad030b92 --- /dev/null +++ b/components/icons/Plus.tsx @@ -0,0 +1,22 @@ +const Plus = ({ ...props }) => { + return ( + + + + + ) +} + +export default Plus diff --git a/components/icons/RightArrow.tsx b/components/icons/RightArrow.tsx new file mode 100644 index 00000000..b7a1579c --- /dev/null +++ b/components/icons/RightArrow.tsx @@ -0,0 +1,29 @@ +const RightArrow = ({ ...props }) => { + return ( + + + + + ) +} + +export default RightArrow diff --git a/components/icons/Sun.tsx b/components/icons/Sun.tsx new file mode 100644 index 00000000..d3684bcb --- /dev/null +++ b/components/icons/Sun.tsx @@ -0,0 +1,28 @@ +const Sun = ({ ...props }) => { + return ( + + + + + + + + + + + + ) +} + +export default Sun diff --git a/components/icons/Trash.tsx b/components/icons/Trash.tsx new file mode 100644 index 00000000..b005ea89 --- /dev/null +++ b/components/icons/Trash.tsx @@ -0,0 +1,43 @@ +const Trash = ({ ...props }) => { + return ( + + + + + + + ) +} + +export default Trash diff --git a/components/icons/Vercel.tsx b/components/icons/Vercel.tsx new file mode 100644 index 00000000..96e619fd --- /dev/null +++ b/components/icons/Vercel.tsx @@ -0,0 +1,40 @@ +const Vercel = ({ ...props }) => { + return ( + + + + + + + + + + ) +} + +export default Vercel diff --git a/components/icons/index.ts b/components/icons/index.ts new file mode 100644 index 00000000..1f208908 --- /dev/null +++ b/components/icons/index.ts @@ -0,0 +1,18 @@ +export { default as Bag } from './Bag' +export { default as Heart } from './Heart' +export { default as Trash } from './Trash' +export { default as Cross } from './Cross' +export { default as ArrowLeft } from './ArrowLeft' +export { default as Plus } from './Plus' +export { default as Minus } from './Minus' +export { default as Check } from './Check' +export { default as Sun } from './Sun' +export { default as Moon } from './Moon' +export { default as Github } from './Github' +export { default as DoubleChevron } from './DoubleChevron' +export { default as RightArrow } from './RightArrow' +export { default as Info } from './Info' +export { default as ChevronUp } from './ChevronUp' +export { default as Vercel } from './Vercel' +export { default as MapPin } from './MapPin' +export { default as CreditCard } from './CreditCard' diff --git a/components/product/ProductCard/ProductCard.module.css b/components/product/ProductCard/ProductCard.module.css new file mode 100644 index 00000000..1484cfaa --- /dev/null +++ b/components/product/ProductCard/ProductCard.module.css @@ -0,0 +1,136 @@ +.root { + @apply relative max-h-full w-full box-border overflow-hidden + bg-no-repeat bg-center bg-cover transition-transform + ease-linear cursor-pointer; + height: 100% !important; + + &:hover { + & .squareBg:before { + transform: scale(0.98); + } + + & .productImage { + transform: scale(1.2625); + } + + & .productTitle > span, + & .productPrice, + & .wishlistButton { + @apply bg-secondary text-secondary; + } + + &:nth-child(6n + 1) .productTitle > span, + &:nth-child(6n + 1) .productPrice, + &:nth-child(6n + 1) .wishlistButton { + @apply bg-violet text-white; + } + + &:nth-child(6n + 5) .productTitle > span, + &:nth-child(6n + 5) .productPrice, + &:nth-child(6n + 5) .wishlistButton { + @apply bg-blue text-white; + } + + &:nth-child(6n + 3) .productTitle > span, + &:nth-child(6n + 3) .productPrice, + &:nth-child(6n + 3) .wishlistButton { + @apply bg-pink text-white; + } + + &:nth-child(6n + 6) .productTitle > span, + &:nth-child(6n + 6) .productPrice, + &:nth-child(6n + 6) .wishlistButton { + @apply bg-cyan text-white; + } + } + + &:nth-child(6n + 1) .squareBg { + @apply bg-violet; + } + + &:nth-child(6n + 5) .squareBg { + @apply bg-blue; + } + + &:nth-child(6n + 3) .squareBg { + @apply bg-pink; + } + + &:nth-child(6n + 6) .squareBg { + @apply bg-cyan; + } +} + +.squareBg, +.productTitle > span, +.productPrice, +.wishlistButton { + @apply transition-colors ease-in-out duration-500; +} + +.squareBg { + @apply transition-colors absolute inset-0 z-0; + background-color: #212529; +} + +.squareBg:before { + @apply transition ease-in-out duration-500 bg-repeat-space w-full h-full block; + background-image: url('/bg-products.svg'); + content: ''; +} + +.simple { + & .squareBg { + @apply bg-accents-0 !important; + background-image: url('/bg-products.svg'); + } + + & .productTitle { + @apply pt-2; + font-size: 1rem; + + & span { + @apply leading-extra-loose; + } + } + + & .productPrice { + @apply text-sm; + } +} + +.productTitle { + @apply pt-0 max-w-full w-full leading-extra-loose; + font-size: 2rem; + letter-spacing: 0.4px; + + & span { + @apply py-4 px-6 bg-primary text-primary font-bold; + font-size: inherit; + letter-spacing: inherit; + box-decoration-break: clone; + -webkit-box-decoration-break: clone; + } +} + +.productPrice { + @apply py-4 px-6 bg-primary text-primary font-semibold inline-block text-sm leading-6; + letter-spacing: 0.4px; +} + +.wishlistButton { + @apply w-10 h-10 flex ml-auto items-center justify-center bg-primary text-primary font-semibold text-xs leading-6 cursor-pointer; +} + +.imageContainer { + @apply flex items-center justify-center; + overflow: hidden; + + & > div { + min-width: 100%; + } +} + +.productImage { + @apply transform transition-transform duration-500 object-cover scale-120; +} diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx new file mode 100644 index 00000000..45a19d2d --- /dev/null +++ b/components/product/ProductCard/ProductCard.tsx @@ -0,0 +1,88 @@ +import { FC } from 'react' +import cn from 'classnames' +import Link from 'next/link' +import type { Product } from '@commerce/types' +import s from './ProductCard.module.css' +import Image, { ImageProps } from 'next/image' +import WishlistButton from '@components/wishlist/WishlistButton' + +interface Props { + className?: string + product: Product + variant?: 'slim' | 'simple' + imgProps?: Omit +} + +const placeholderImg = '/product-img-placeholder.svg' + +const ProductCard: FC = ({ + className, + product, + variant, + imgProps, + ...props +}) => ( + + + {variant === 'slim' ? ( +
    +
    + + {product.name} + +
    + {product?.images && ( + {product.name + )} +
    + ) : ( + <> +
    +
    +
    +

    + {product.name} +

    + + {product.price.value} +   + {product.price.currencyCode} + +
    + {process.env.COMMERCE_WISHLIST_ENABLED && ( + + )} +
    +
    + {product?.images && ( + {product.name + )} +
    + + )} +
    + +) + +export default ProductCard diff --git a/components/product/ProductCard/index.ts b/components/product/ProductCard/index.ts new file mode 100644 index 00000000..4559faa1 --- /dev/null +++ b/components/product/ProductCard/index.ts @@ -0,0 +1 @@ +export { default } from './ProductCard' diff --git a/components/product/ProductSlider/ProductSlider.module.css b/components/product/ProductSlider/ProductSlider.module.css new file mode 100644 index 00000000..259d1580 --- /dev/null +++ b/components/product/ProductSlider/ProductSlider.module.css @@ -0,0 +1,82 @@ +.root { + @apply relative w-full h-full; + overflow-y: hidden; +} + +.leftControl, +.rightControl { + @apply absolute top-1/2 -translate-x-1/2 z-20 w-16 h-16 flex items-center justify-center bg-hover-1 rounded-full; +} + +.leftControl:hover, +.rightControl:hover { + @apply bg-hover-2; +} + +.leftControl:hover, +.rightControl:hover { + @apply outline-none shadow-outline-normal; +} + +.leftControl { + @apply bg-cover left-10; + background-image: url('public/cursor-left.png'); + + @screen md { + @apply left-6; + } +} + +.rightControl { + @apply bg-cover right-10; + background-image: url('public/cursor-right.png'); + + @screen md { + @apply right-6; + } +} + +.control { + @apply opacity-0 transition duration-150; +} + +.root:hover .control { + @apply opacity-100; +} + +.positionIndicatorsContainer { + @apply hidden; + + @screen sm { + @apply block absolute bottom-6 left-1/2; + transform: translateX(-50%); + } +} + +.positionIndicator { + @apply rounded-full p-2; +} + +.dot { + @apply bg-hover-1 transition w-3 h-3 rounded-full; +} + +.positionIndicator:hover .dot { + @apply bg-hover-2; +} + +.positionIndicator:focus { + @apply outline-none; +} + +.positionIndicator:focus .dot { + @apply shadow-outline-normal; +} + +.positionIndicatorActive .dot { + @apply bg-white; +} + +.positionIndicatorActive:hover .dot { + @apply bg-white; +} diff --git a/components/product/ProductSlider/ProductSlider.tsx b/components/product/ProductSlider/ProductSlider.tsx new file mode 100644 index 00000000..02244f5b --- /dev/null +++ b/components/product/ProductSlider/ProductSlider.tsx @@ -0,0 +1,119 @@ +import { useKeenSlider } from 'keen-slider/react' +import React, { + Children, + FC, + isValidElement, + useState, + useRef, + useEffect, +} from 'react' +import cn from 'classnames' + +import s from './ProductSlider.module.css' + +const ProductSlider: FC = ({ children }) => { + const [currentSlide, setCurrentSlide] = useState(0) + const [isMounted, setIsMounted] = useState(false) + const sliderContainerRef = useRef(null) + + const [ref, slider] = useKeenSlider({ + loop: true, + slidesPerView: 1, + mounted: () => setIsMounted(true), + slideChanged(s) { + setCurrentSlide(s.details().relativeSlide) + }, + }) + + // Stop the history navigation gesture on touch devices + useEffect(() => { + const preventNavigation = (event: TouchEvent) => { + // Center point of the touch area + const touchXPosition = event.touches[0].pageX + // Size of the touch area + const touchXRadius = event.touches[0].radiusX || 0 + + // We set a threshold (10px) on both sizes of the screen, + // if the touch area overlaps with the screen edges + // it's likely to trigger the navigation. We prevent the + // touchstart event in that case. + if ( + touchXPosition - touchXRadius < 10 || + touchXPosition + touchXRadius > window.innerWidth - 10 + ) + event.preventDefault() + } + + sliderContainerRef.current!.addEventListener( + 'touchstart', + preventNavigation + ) + + return () => { + if (sliderContainerRef.current) { + sliderContainerRef.current!.removeEventListener( + 'touchstart', + preventNavigation + ) + } + } + }, []) + + return ( +
    + + ) + })} +
    + )} +
    + ) +} + +export default ProductSlider diff --git a/components/product/ProductSlider/index.ts b/components/product/ProductSlider/index.ts new file mode 100644 index 00000000..50444041 --- /dev/null +++ b/components/product/ProductSlider/index.ts @@ -0,0 +1 @@ +export { default } from './ProductSlider' diff --git a/components/product/ProductView/ProductView.module.css b/components/product/ProductView/ProductView.module.css new file mode 100644 index 00000000..6545d611 --- /dev/null +++ b/components/product/ProductView/ProductView.module.css @@ -0,0 +1,96 @@ +.root { + @apply relative grid items-start gap-8 grid-cols-1 overflow-x-hidden; + + @screen lg { + @apply grid-cols-12; + } +} + +.productDisplay { + @apply relative flex px-0 pb-0 box-border col-span-1 bg-violet; + min-height: 600px; + + @screen md { + min-height: 700px; + } + + @screen lg { + margin-right: -2rem; + margin-left: -2rem; + @apply mx-0 col-span-6; + min-height: 100%; + height: 100%; + } +} + +.squareBg { + @apply absolute inset-0 bg-violet z-0 h-full; +} + +.nameBox { + @apply absolute top-6 left-0 z-20 pr-16; + + @screen lg { + @apply left-6 pr-16; + } + + & .name { + @apply px-6 py-2 bg-primary text-primary font-bold; + font-size: 2rem; + letter-spacing: 0.4px; + } + + & .price { + @apply px-6 py-2 pb-4 bg-primary text-primary font-bold inline-block tracking-wide; + } + + @screen lg { + & .name, + & .price { + @apply bg-violet-light text-white; + } + } +} + +.sidebar { + @apply flex flex-col col-span-1 mx-auto max-w-8xl px-6 w-full h-full; + + @screen lg { + @apply col-span-6 py-24 justify-between; + } +} + +.sliderContainer { + @apply absolute z-10 inset-0 flex items-center justify-center overflow-x-hidden; +} + +.imageContainer { + & > div { + @apply h-full; + & > div { + @apply h-full; + } + } +} + +.img { + @apply w-full h-auto max-h-full object-cover; +} + +.button { + text-align: center; + width: 100%; + max-width: 300px; + + @screen sm { + min-width: 300px; + } +} + +.wishlistButton { + @apply absolute z-30 top-6 right-0 bg-primary text-primary w-10 h-10 flex items-center justify-center font-semibold leading-6 cursor-pointer; + + @screen lg { + @apply right-12 text-white bg-violet; + } +} diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx new file mode 100644 index 00000000..d38da352 --- /dev/null +++ b/components/product/ProductView/ProductView.tsx @@ -0,0 +1,174 @@ +import cn from 'classnames' +import Image from 'next/image' +import { NextSeo } from 'next-seo' +import { FC, useEffect, useState } from 'react' +import s from './ProductView.module.css' +import { Swatch, ProductSlider } from '@components/product' +import { Button, Container, Text, useUI } from '@components/ui' +import type { Product } from '@commerce/types' +import usePrice from '@framework/product/use-price' +import { useAddItem } from '@framework/cart' +import { getVariant, SelectedOptions } from '../helpers' +import WishlistButton from '@components/wishlist/WishlistButton' + +interface Props { + children?: any + product: Product + className?: string +} + +const ProductView: FC = ({ product }) => { + const addItem = useAddItem() + const { price } = usePrice({ + amount: product.price.value, + baseAmount: product.price.retailPrice, + currencyCode: product.price.currencyCode!, + }) + const { openSidebar } = useUI() + const [loading, setLoading] = useState(false) + const [choices, setChoices] = useState({}) + + useEffect(() => { + // Selects the default option + product.variants[0].options?.forEach((v) => { + setChoices((choices) => ({ + ...choices, + [v.displayName.toLowerCase()]: v.values[0].label.toLowerCase(), + })) + }) + }, []) + + const variant = getVariant(product, choices) + + const addToCart = async () => { + setLoading(true) + try { + const selectedVariant = variant ? variant : product.variants[0] + + console.log('selected variant', selectedVariant) + + await addItem({ + productId: String(product.id), + variantId: String(selectedVariant.id), + pricing: { + amount: selectedVariant.price, + currencyCode: product.price.currencyCode ?? 'USD', + }, + }) + openSidebar() + setLoading(false) + } catch (err) { + setLoading(false) + } + } + + return ( + + +
    +
    +
    +

    {product.name}

    +
    + {price} + {` `} + {product.price?.currencyCode} +
    +
    + +
    + + {product.images.map((image, i) => ( +
    + {image.alt +
    + ))} +
    +
    +
    +
    +
    + {product.options?.map((opt) => ( +
    +

    {opt.displayName}

    +
    + {opt.values.map((v, i: number) => { + const active = (choices as any)[ + opt.displayName.toLowerCase() + ] + + return ( + { + setChoices((choices) => { + return { + ...choices, + [opt.displayName.toLowerCase()]: v.label.toLowerCase(), + } + }) + }} + /> + ) + })} +
    +
    + ))} + +
    + +
    +
    +
    + +
    +
    + {process.env.COMMERCE_WISHLIST_ENABLED && ( + + )} +
    +
    + ) +} + +export default ProductView diff --git a/components/product/ProductView/index.ts b/components/product/ProductView/index.ts new file mode 100644 index 00000000..9ac14480 --- /dev/null +++ b/components/product/ProductView/index.ts @@ -0,0 +1 @@ +export { default } from './ProductView' diff --git a/components/product/Swatch/Swatch.module.css b/components/product/Swatch/Swatch.module.css new file mode 100644 index 00000000..051435af --- /dev/null +++ b/components/product/Swatch/Swatch.module.css @@ -0,0 +1,33 @@ +.root { + composes: root from 'components/ui/Button/Button.module.css'; + @apply h-12 w-12 bg-primary text-primary rounded-full mr-3 inline-flex + items-center justify-center cursor-pointer transition duration-150 ease-in-out + p-0 shadow-none border-gray-200 border box-border; + + & > span { + @apply absolute; + } + + &:hover { + @apply transform scale-110 bg-hover; + } +} + +.color { + @apply text-black transition duration-150 ease-in-out; + + &:hover { + @apply text-black; + } + + &.dark, + &.dark:hover { + color: white !important; + } +} + +.active { + &.size { + @apply border-accents-9 border-2; + } +} diff --git a/components/product/Swatch/Swatch.tsx b/components/product/Swatch/Swatch.tsx new file mode 100644 index 00000000..34244321 --- /dev/null +++ b/components/product/Swatch/Swatch.tsx @@ -0,0 +1,55 @@ +import cn from 'classnames' +import { FC } from 'react' +import s from './Swatch.module.css' +import { Check } from '@components/icons' +import Button, { ButtonProps } from '@components/ui/Button' +import { isDark } from '@lib/colors' +interface Props { + active?: boolean + children?: any + className?: string + label?: string + variant?: 'size' | 'color' | string + color?: string +} + +const Swatch: FC & Props> = ({ + className, + color = '', + label, + variant = 'size', + active, + ...props +}) => { + variant = variant?.toLowerCase() + label = label?.toLowerCase() + + const rootClassName = cn( + s.root, + { + [s.active]: active, + [s.size]: variant === 'size', + [s.color]: color, + [s.dark]: color ? isDark(color) : false, + }, + className + ) + + return ( + + ) +} + +export default Swatch diff --git a/components/product/Swatch/index.ts b/components/product/Swatch/index.ts new file mode 100644 index 00000000..c8a79549 --- /dev/null +++ b/components/product/Swatch/index.ts @@ -0,0 +1 @@ +export { default } from './Swatch' diff --git a/components/product/helpers.ts b/components/product/helpers.ts new file mode 100644 index 00000000..a0ceb7aa --- /dev/null +++ b/components/product/helpers.ts @@ -0,0 +1,18 @@ +import type { Product } from '@commerce/types' +export type SelectedOptions = Record + +export function getVariant(product: Product, opts: SelectedOptions) { + const variant = product.variants.find((variant) => { + return Object.entries(opts).every(([key, value]) => + variant.options.find((option) => { + if ( + option.__typename === 'MultipleChoiceOption' && + option.displayName.toLowerCase() === key.toLowerCase() + ) { + return option.values.find((v) => v.label.toLowerCase() === value) + } + }) + ) + }) + return variant +} diff --git a/components/product/index.ts b/components/product/index.ts new file mode 100644 index 00000000..82ac6c54 --- /dev/null +++ b/components/product/index.ts @@ -0,0 +1,4 @@ +export { default as Swatch } from './Swatch' +export { default as ProductView } from './ProductView' +export { default as ProductCard } from './ProductCard' +export { default as ProductSlider } from './ProductSlider' diff --git a/components/ui/Button/Button.module.css b/components/ui/Button/Button.module.css new file mode 100644 index 00000000..5b563f49 --- /dev/null +++ b/components/ui/Button/Button.module.css @@ -0,0 +1,32 @@ +.root { + @apply bg-secondary text-accents-1 cursor-pointer inline-flex px-10 rounded-sm leading-6 transition ease-in-out duration-150 shadow-sm font-semibold text-center justify-center uppercase py-4 border border-transparent items-center; +} + +.root:hover { + @apply bg-accents-0 text-primary border border-secondary; +} + +.root:focus { + @apply shadow-outline-normal outline-none; +} + +.root[data-active] { + @apply bg-gray-600; +} + +.loading { + @apply bg-accents-1 text-accents-3 border-accents-2 cursor-not-allowed; +} + +.slim { + @apply py-2 transform-none normal-case; +} + +.disabled, +.disabled:hover { + @apply text-accents-4 border-accents-2 bg-accents-1 cursor-not-allowed; + filter: grayscale(1); + -webkit-transform: translateZ(0); + -webkit-perspective: 1000; + -webkit-backface-visibility: hidden; +} diff --git a/components/ui/Button/Button.tsx b/components/ui/Button/Button.tsx new file mode 100644 index 00000000..ca5db36a --- /dev/null +++ b/components/ui/Button/Button.tsx @@ -0,0 +1,72 @@ +import cn from 'classnames' +import React, { + forwardRef, + ButtonHTMLAttributes, + JSXElementConstructor, + useRef, +} from 'react' +import mergeRefs from 'react-merge-refs' +import s from './Button.module.css' +import { LoadingDots } from '@components/ui' + +export interface ButtonProps extends ButtonHTMLAttributes { + href?: string + className?: string + variant?: 'flat' | 'slim' + active?: boolean + type?: 'submit' | 'reset' | 'button' + Component?: string | JSXElementConstructor + width?: string | number + loading?: boolean + disabled?: boolean +} + +const Button: React.FC = forwardRef((props, buttonRef) => { + const { + className, + variant = 'flat', + children, + active, + width, + loading = false, + disabled = false, + style = {}, + Component = 'button', + ...rest + } = props + const ref = useRef(null) + + const rootClassName = cn( + s.root, + { + [s.slim]: variant === 'slim', + [s.loading]: loading, + [s.disabled]: disabled, + }, + className + ) + + return ( + + {children} + {loading && ( + + + + )} + + ) +}) + +export default Button diff --git a/components/ui/Button/index.ts b/components/ui/Button/index.ts new file mode 100644 index 00000000..aa076c58 --- /dev/null +++ b/components/ui/Button/index.ts @@ -0,0 +1,2 @@ +export { default } from './Button' +export * from './Button' diff --git a/components/ui/Container/Container.tsx b/components/ui/Container/Container.tsx new file mode 100644 index 00000000..7b281a2e --- /dev/null +++ b/components/ui/Container/Container.tsx @@ -0,0 +1,23 @@ +import cn from 'classnames' +import React, { FC } from 'react' + +interface Props { + className?: string + children?: any + el?: HTMLElement + clean?: boolean +} + +const Container: FC = ({ children, className, el = 'div', clean }) => { + const rootClassName = cn(className, { + 'mx-auto max-w-8xl px-6': !clean, + }) + + let Component: React.ComponentType< + React.HTMLAttributes + > = el as any + + return {children} +} + +export default Container diff --git a/components/ui/Container/index.ts b/components/ui/Container/index.ts new file mode 100644 index 00000000..9dbd596a --- /dev/null +++ b/components/ui/Container/index.ts @@ -0,0 +1 @@ +export { default } from './Container' diff --git a/components/ui/Grid/Grid.module.css b/components/ui/Grid/Grid.module.css new file mode 100644 index 00000000..9b331be8 --- /dev/null +++ b/components/ui/Grid/Grid.module.css @@ -0,0 +1,156 @@ +.root { + --row-height: calc(100vh - 88px); + @apply grid grid-cols-1 gap-0; + min-height: var(--row-height); + + & > * { + @apply row-span-1 bg-transparent box-border overflow-hidden; + height: 500px; + max-height: 800px; + + @screen lg { + @apply col-span-1; + height: inherit; + } + } +} + +@screen lg { + .root { + @apply grid-cols-3 grid-rows-2; + } + + .root & > * { + @apply col-span-1; + height: inherit; + } +} + +.default { + & > * { + @apply bg-transparent; + } +} + +.layoutNormal { + @apply gap-3; + + & > * { + min-height: 325px; + } +} + +.layoutA { + & > *:nth-child(6n + 1), + & > *:nth-child(6n + 5) { + @apply row-span-2; + height: var(--row-height); + + @screen lg { + @apply col-span-2; + } + } + + &.filled { + & > *:nth-child(6n + 1), + & > *:nth-child(6n + 5) { + @apply bg-violet; + } + + & > *:nth-child(6n + 5) { + @apply bg-blue; + } + + & > *:nth-child(6n + 3) { + @apply bg-pink; + } + + & > *:nth-child(6n + 6) { + @apply bg-cyan; + } + } +} + +.layoutB { + & > *:nth-child(6n + 2), + & > *:nth-child(6n + 4) { + @apply row-span-2; + height: var(--row-height); + + @screen lg { + @apply col-span-2; + } + } + + &.filled { + & > *:nth-child(6n + 2) { + @apply bg-blue; + } + + & > *:nth-child(6n + 4) { + @apply bg-violet; + } + + & > *:nth-child(6n + 3) { + @apply bg-pink; + } + + & > *:nth-child(6n + 6) { + @apply bg-cyan; + } + } +} + +.layoutC { + & > *:nth-child(12n + 1), + & > *:nth-child(12n + 8) { + @apply row-span-2; + height: var(--row-height); + + @screen lg { + @apply col-span-2; + } + } + + &.filled { + & > *:nth-child(12n + 1) { + @apply bg-violet; + height: var(--row-height); + } + + & > *:nth-child(12n + 8) { + @apply bg-cyan; + height: var(--row-height); + } + + & > *:nth-child(6n + 3) { + @apply bg-pink; + } + } +} + +.layoutD { + & > *:nth-child(12n + 2), + & > *:nth-child(12n + 7) { + @apply row-span-2; + height: var(--row-height); + + @screen lg { + @apply col-span-2; + } + } + + &.filled { + & > *:nth-child(12n + 2) { + @apply bg-violet; + } + + & > *:nth-child(12n + 7) { + @apply bg-cyan; + } + + & > *:nth-child(6n + 3) { + @apply bg-pink; + } + } +} diff --git a/components/ui/Grid/Grid.tsx b/components/ui/Grid/Grid.tsx new file mode 100644 index 00000000..8ca24760 --- /dev/null +++ b/components/ui/Grid/Grid.tsx @@ -0,0 +1,34 @@ +import cn from 'classnames' +import { FC, ReactNode, Component } from 'react' +import s from './Grid.module.css' + +interface Props { + className?: string + children?: ReactNode[] | Component[] | any[] + layout?: 'A' | 'B' | 'C' | 'D' | 'normal' + variant?: 'default' | 'filled' +} + +const Grid: FC = ({ + className, + layout = 'A', + children, + variant = 'default', +}) => { + const rootClassName = cn( + s.root, + { + [s.layoutA]: layout === 'A', + [s.layoutB]: layout === 'B', + [s.layoutC]: layout === 'C', + [s.layoutD]: layout === 'D', + [s.layoutNormal]: layout === 'normal', + [s.default]: variant === 'default', + [s.filled]: variant === 'filled', + }, + className + ) + return
    {children}
    +} + +export default Grid diff --git a/components/ui/Grid/index.ts b/components/ui/Grid/index.ts new file mode 100644 index 00000000..ddb51299 --- /dev/null +++ b/components/ui/Grid/index.ts @@ -0,0 +1 @@ +export { default } from './Grid' diff --git a/components/ui/Hero/Hero.module.css b/components/ui/Hero/Hero.module.css new file mode 100644 index 00000000..c2032c8a --- /dev/null +++ b/components/ui/Hero/Hero.module.css @@ -0,0 +1,9 @@ +.root { + @apply mx-auto grid grid-cols-1 py-32 gap-4; +} + +@screen md { + .root { + @apply grid-cols-2; + } +} diff --git a/components/ui/Hero/Hero.tsx b/components/ui/Hero/Hero.tsx new file mode 100644 index 00000000..1802f9ee --- /dev/null +++ b/components/ui/Hero/Hero.tsx @@ -0,0 +1,37 @@ +import React, { FC } from 'react' +import { Container } from '@components/ui' +import { RightArrow } from '@components/icons' +import s from './Hero.module.css' +import Link from 'next/link' +interface Props { + className?: string + headline: string + description: string +} + +const Hero: FC = ({ headline, description }) => { + return ( +
    + +
    +

    + {headline} +

    +
    +

    + {description} +

    + + + Read it here + + + +
    +
    +
    +
    + ) +} + +export default Hero diff --git a/components/ui/Hero/index.ts b/components/ui/Hero/index.ts new file mode 100644 index 00000000..b08fa5ac --- /dev/null +++ b/components/ui/Hero/index.ts @@ -0,0 +1 @@ +export { default } from './Hero' diff --git a/components/ui/Input/Input.module.css b/components/ui/Input/Input.module.css new file mode 100644 index 00000000..9daee141 --- /dev/null +++ b/components/ui/Input/Input.module.css @@ -0,0 +1,7 @@ +.root { + @apply bg-primary py-2 px-6 w-full appearance-none transition duration-150 ease-in-out pr-10 border border-accents-3 text-accents-6; +} + +.root:focus { + @apply outline-none shadow-outline-normal; +} diff --git a/components/ui/Input/Input.tsx b/components/ui/Input/Input.tsx new file mode 100644 index 00000000..dc2f04a8 --- /dev/null +++ b/components/ui/Input/Input.tsx @@ -0,0 +1,37 @@ +import cn from 'classnames' +import s from './Input.module.css' +import React, { InputHTMLAttributes } from 'react' + +export interface Props extends InputHTMLAttributes { + className?: string + onChange?: (...args: any[]) => any +} + +const Input: React.FC = (props) => { + const { className, children, onChange, ...rest } = props + + const rootClassName = cn(s.root, {}, className) + + const handleOnChange = (e: any) => { + if (onChange) { + onChange(e.target.value) + } + return null + } + + return ( + + ) +} + +export default Input diff --git a/components/ui/Input/index.ts b/components/ui/Input/index.ts new file mode 100644 index 00000000..aa97178e --- /dev/null +++ b/components/ui/Input/index.ts @@ -0,0 +1 @@ +export { default } from './Input' diff --git a/components/ui/Link/Link.tsx b/components/ui/Link/Link.tsx new file mode 100644 index 00000000..27f30e86 --- /dev/null +++ b/components/ui/Link/Link.tsx @@ -0,0 +1,11 @@ +import NextLink, { LinkProps as NextLinkProps } from 'next/link' + +const Link: React.FC = ({ href, children, ...props }) => { + return ( + + {children} + + ) +} + +export default Link diff --git a/components/ui/Link/index.ts b/components/ui/Link/index.ts new file mode 100644 index 00000000..518d3729 --- /dev/null +++ b/components/ui/Link/index.ts @@ -0,0 +1 @@ +export { default } from './Link' diff --git a/components/ui/LoadingDots/LoadingDots.module.css b/components/ui/LoadingDots/LoadingDots.module.css new file mode 100644 index 00000000..88ce77ec --- /dev/null +++ b/components/ui/LoadingDots/LoadingDots.module.css @@ -0,0 +1,32 @@ +.root { + @apply inline-flex text-center items-center leading-7; + + & span { + @apply bg-accents-6 rounded-full h-2 w-2; + animation-name: blink; + animation-duration: 1.4s; + animation-iteration-count: infinite; + animation-fill-mode: both; + margin: 0 2px; + + &:nth-of-type(2) { + animation-delay: 0.2s; + } + + &:nth-of-type(3) { + animation-delay: 0.4s; + } + } +} + +@keyframes blink { + 0% { + opacity: 0.2; + } + 20% { + opacity: 1; + } + 100% { + opacity: 0.2; + } +} diff --git a/components/ui/LoadingDots/LoadingDots.tsx b/components/ui/LoadingDots/LoadingDots.tsx new file mode 100644 index 00000000..10e5bbae --- /dev/null +++ b/components/ui/LoadingDots/LoadingDots.tsx @@ -0,0 +1,13 @@ +import s from './LoadingDots.module.css' + +const LoadingDots: React.FC = () => { + return ( + + + + + + ) +} + +export default LoadingDots diff --git a/components/ui/LoadingDots/index.ts b/components/ui/LoadingDots/index.ts new file mode 100644 index 00000000..63df282b --- /dev/null +++ b/components/ui/LoadingDots/index.ts @@ -0,0 +1 @@ +export { default } from './LoadingDots' diff --git a/components/ui/Logo/Logo.tsx b/components/ui/Logo/Logo.tsx new file mode 100644 index 00000000..f15bde40 --- /dev/null +++ b/components/ui/Logo/Logo.tsx @@ -0,0 +1,21 @@ +const Logo = ({ className = '', ...props }) => ( + + + + +) + +export default Logo diff --git a/components/ui/Logo/index.ts b/components/ui/Logo/index.ts new file mode 100644 index 00000000..93dce23b --- /dev/null +++ b/components/ui/Logo/index.ts @@ -0,0 +1 @@ +export { default } from './Logo' diff --git a/components/ui/Marquee/Marquee.module.css b/components/ui/Marquee/Marquee.module.css new file mode 100644 index 00000000..1fabc2ca --- /dev/null +++ b/components/ui/Marquee/Marquee.module.css @@ -0,0 +1,22 @@ +.root { + @apply w-full relative; + height: 320px; + min-width: 100%; +} + +.container { + @apply flex flex-row items-center; +} + +.container > * { + @apply relative flex-1 px-16 py-4 h-full; + min-height: 320px; +} + +.primary { + @apply bg-white; +} + +.secondary { + @apply bg-black; +} diff --git a/components/ui/Marquee/Marquee.tsx b/components/ui/Marquee/Marquee.tsx new file mode 100644 index 00000000..163f29a3 --- /dev/null +++ b/components/ui/Marquee/Marquee.tsx @@ -0,0 +1,35 @@ +import cn from 'classnames' +import s from './Marquee.module.css' +import { FC, ReactNode, Component } from 'react' +import Ticker from 'react-ticker' + +interface Props { + className?: string + children?: ReactNode[] | Component[] | any[] + variant?: 'primary' | 'secondary' +} + +const Marquee: FC = ({ + className = '', + children, + variant = 'primary', +}) => { + const rootClassName = cn( + s.root, + { + [s.primary]: variant === 'primary', + [s.secondary]: variant === 'secondary', + }, + className + ) + + return ( +
    + + {() =>
    {children}
    } +
    +
    + ) +} + +export default Marquee diff --git a/components/ui/Marquee/index.ts b/components/ui/Marquee/index.ts new file mode 100644 index 00000000..b59b7556 --- /dev/null +++ b/components/ui/Marquee/index.ts @@ -0,0 +1 @@ +export { default } from './Marquee' diff --git a/components/ui/Modal/Modal.module.css b/components/ui/Modal/Modal.module.css new file mode 100644 index 00000000..693bc2d3 --- /dev/null +++ b/components/ui/Modal/Modal.module.css @@ -0,0 +1,12 @@ +.root { + @apply fixed bg-primary text-primary flex items-center inset-0 z-50 justify-center; + background-color: rgba(0, 0, 0, 0.35); +} + +.modal { + @apply bg-primary p-12 border border-accents-2 relative; +} + +.modal:focus { + @apply outline-none; +} diff --git a/components/ui/Modal/Modal.tsx b/components/ui/Modal/Modal.tsx new file mode 100644 index 00000000..300a9919 --- /dev/null +++ b/components/ui/Modal/Modal.tsx @@ -0,0 +1,66 @@ +import { FC, useRef, useEffect, useCallback } from 'react' +import Portal from '@reach/portal' +import s from './Modal.module.css' +import { Cross } from '@components/icons' +import { + disableBodyScroll, + enableBodyScroll, + clearAllBodyScrollLocks, +} from 'body-scroll-lock' +import FocusTrap from '@lib/focus-trap' +interface Props { + className?: string + children?: any + open?: boolean + onClose: () => void + onEnter?: () => void | null +} + +const Modal: FC = ({ children, open, onClose, onEnter = null }) => { + const ref = useRef() as React.MutableRefObject + + const handleKey = useCallback( + (e: KeyboardEvent) => { + if (e.key === 'Escape') { + return onClose() + } + }, + [onClose] + ) + + useEffect(() => { + if (ref.current) { + if (open) { + disableBodyScroll(ref.current) + window.addEventListener('keydown', handleKey) + } else { + enableBodyScroll(ref.current) + } + } + return () => { + window.removeEventListener('keydown', handleKey) + clearAllBodyScrollLocks() + } + }, [open, handleKey]) + + return ( + + {open ? ( +
    +
    + + {children} +
    +
    + ) : null} +
    + ) +} + +export default Modal diff --git a/components/ui/Modal/index.ts b/components/ui/Modal/index.ts new file mode 100644 index 00000000..e24753a1 --- /dev/null +++ b/components/ui/Modal/index.ts @@ -0,0 +1 @@ +export { default } from './Modal' diff --git a/components/ui/README.md b/components/ui/README.md new file mode 100644 index 00000000..5bf4fe51 --- /dev/null +++ b/components/ui/README.md @@ -0,0 +1,3 @@ +# UI + +Building blocks to build a rich graphical interfaces. Components should be atomic and pure. Serve one purpose. diff --git a/components/ui/Sidebar/Sidebar.module.css b/components/ui/Sidebar/Sidebar.module.css new file mode 100644 index 00000000..b9ba054e --- /dev/null +++ b/components/ui/Sidebar/Sidebar.module.css @@ -0,0 +1,3 @@ +.root { + @apply fixed inset-0 overflow-hidden h-full z-50; +} diff --git a/components/ui/Sidebar/Sidebar.tsx b/components/ui/Sidebar/Sidebar.tsx new file mode 100644 index 00000000..a0d5e833 --- /dev/null +++ b/components/ui/Sidebar/Sidebar.tsx @@ -0,0 +1,55 @@ +import s from './Sidebar.module.css' +import Portal from '@reach/portal' +import { FC, useEffect, useRef } from 'react' +import { + disableBodyScroll, + enableBodyScroll, + clearAllBodyScrollLocks, +} from 'body-scroll-lock' + +interface Props { + children: any + open: boolean + onClose: () => void +} + +const Sidebar: FC = ({ children, open = false, onClose }) => { + const ref = useRef() as React.MutableRefObject + + useEffect(() => { + if (ref.current) { + if (open) { + disableBodyScroll(ref.current) + } else { + enableBodyScroll(ref.current) + } + } + return () => { + clearAllBodyScrollLocks() + } + }, [open]) + + return ( + + {open ? ( +
    +
    +
    +
    +
    +
    + {children} +
    +
    +
    +
    +
    + ) : null} + + ) +} + +export default Sidebar diff --git a/components/ui/Sidebar/index.ts b/components/ui/Sidebar/index.ts new file mode 100644 index 00000000..877187ca --- /dev/null +++ b/components/ui/Sidebar/index.ts @@ -0,0 +1 @@ +export { default } from './Sidebar' diff --git a/components/ui/Skeleton/Skeleton.module.css b/components/ui/Skeleton/Skeleton.module.css new file mode 100644 index 00000000..5a852562 --- /dev/null +++ b/components/ui/Skeleton/Skeleton.module.css @@ -0,0 +1,48 @@ +.skeleton { + @apply block; + background-image: linear-gradient( + 270deg, + var(--accents-1), + var(--accents-2), + var(--accents-2), + var(--accents-1) + ); + background-size: 400% 100%; + animation: loading 8s ease-in-out infinite; +} + +.wrapper { + @apply block relative; + + &:not(.show)::before { + content: none; + } + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 100; + background-image: linear-gradient( + 270deg, + var(--accents-1), + var(--accents-2), + var(--accents-2), + var(--accents-1) + ); + background-size: 400% 100%; + animation: loading 8s ease-in-out infinite; + } +} + +@keyframes loading { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} diff --git a/components/ui/Skeleton/Skeleton.tsx b/components/ui/Skeleton/Skeleton.tsx new file mode 100644 index 00000000..153024f1 --- /dev/null +++ b/components/ui/Skeleton/Skeleton.tsx @@ -0,0 +1,57 @@ +import React, { CSSProperties } from 'react' +import cn from 'classnames' +import px from '@lib/to-pixels' +import s from './Skeleton.module.css' + +interface Props { + width?: string | number + height?: string | number + boxHeight?: string | number + style?: CSSProperties + show?: boolean + block?: boolean + className?: string +} + +const Skeleton: React.FC = ({ + style, + width, + height, + children, + className, + show = true, + boxHeight = height, +}) => { + // Automatically calculate the size if there are children + // and no fixed sizes are specified + const shouldAutoSize = !!children && !(width || height) + + // Defaults + width = width || 24 + height = height || 24 + boxHeight = boxHeight || height + + return ( + + {children} + + ) +} + +export default Skeleton diff --git a/components/ui/Skeleton/index.ts b/components/ui/Skeleton/index.ts new file mode 100644 index 00000000..3ec6c003 --- /dev/null +++ b/components/ui/Skeleton/index.ts @@ -0,0 +1 @@ +export { default } from './Skeleton' diff --git a/components/ui/Text/Text.module.css b/components/ui/Text/Text.module.css new file mode 100644 index 00000000..bbdfb6a0 --- /dev/null +++ b/components/ui/Text/Text.module.css @@ -0,0 +1,15 @@ +.body { + @apply text-lg leading-7 font-medium max-w-6xl mx-auto; +} + +.heading { + @apply text-5xl mb-12; +} + +.pageHeading { + @apply pt-1 pb-4 text-2xl leading-7 font-bold tracking-wide; +} + +.sectionHeading { + @apply pt-1 pb-2 font-semibold leading-7 tracking-wider uppercase border-b border-accents-2 mb-3; +} diff --git a/components/ui/Text/Text.tsx b/components/ui/Text/Text.tsx new file mode 100644 index 00000000..51e1cce1 --- /dev/null +++ b/components/ui/Text/Text.tsx @@ -0,0 +1,67 @@ +import React, { + FunctionComponent, + JSXElementConstructor, + CSSProperties, +} from 'react' +import cn from 'classnames' +import s from './Text.module.css' + +interface Props { + variant?: Variant + className?: string + style?: CSSProperties + children?: React.ReactNode | any + html?: string +} + +type Variant = 'heading' | 'body' | 'pageHeading' | 'sectionHeading' + +const Text: FunctionComponent = ({ + style, + className = '', + variant = 'body', + children, + html, +}) => { + const componentsMap: { + [P in Variant]: React.ComponentType | string + } = { + body: 'div', + heading: 'h1', + pageHeading: 'h1', + sectionHeading: 'h2', + } + + const Component: + | JSXElementConstructor + | React.ReactElement + | React.ComponentType + | string = componentsMap![variant!] + + const htmlContentProps = html + ? { + dangerouslySetInnerHTML: { __html: html }, + } + : {} + + return ( + + {children} + + ) +} + +export default Text diff --git a/components/ui/Text/index.ts b/components/ui/Text/index.ts new file mode 100644 index 00000000..e1e5fa74 --- /dev/null +++ b/components/ui/Text/index.ts @@ -0,0 +1 @@ +export { default } from './Text' diff --git a/components/ui/context.tsx b/components/ui/context.tsx new file mode 100644 index 00000000..f66adb9d --- /dev/null +++ b/components/ui/context.tsx @@ -0,0 +1,207 @@ +import React, { FC, useMemo } from 'react' +import { ThemeProvider } from 'next-themes' + +export interface State { + displaySidebar: boolean + displayDropdown: boolean + displayModal: boolean + displayToast: boolean + modalView: string + toastText: string + userAvatar: string +} + +const initialState = { + displaySidebar: false, + displayDropdown: false, + displayModal: false, + modalView: 'LOGIN_VIEW', + displayToast: false, + toastText: '', + userAvatar: '', +} + +type Action = + | { + type: 'OPEN_SIDEBAR' + } + | { + type: 'CLOSE_SIDEBAR' + } + | { + type: 'OPEN_TOAST' + } + | { + type: 'CLOSE_TOAST' + } + | { + type: 'SET_TOAST_TEXT' + text: ToastText + } + | { + type: 'OPEN_DROPDOWN' + } + | { + type: 'CLOSE_DROPDOWN' + } + | { + type: 'OPEN_MODAL' + } + | { + type: 'CLOSE_MODAL' + } + | { + type: 'SET_MODAL_VIEW' + view: MODAL_VIEWS + } + | { + type: 'SET_USER_AVATAR' + value: string + } + +type MODAL_VIEWS = + | 'SIGNUP_VIEW' + | 'LOGIN_VIEW' + | 'FORGOT_VIEW' + | 'NEW_SHIPPING_ADDRESS' + | 'NEW_PAYMENT_METHOD' +type ToastText = string + +export const UIContext = React.createContext(initialState) + +UIContext.displayName = 'UIContext' + +function uiReducer(state: State, action: Action) { + switch (action.type) { + case 'OPEN_SIDEBAR': { + return { + ...state, + displaySidebar: true, + } + } + case 'CLOSE_SIDEBAR': { + return { + ...state, + displaySidebar: false, + } + } + case 'OPEN_DROPDOWN': { + return { + ...state, + displayDropdown: true, + } + } + case 'CLOSE_DROPDOWN': { + return { + ...state, + displayDropdown: false, + } + } + case 'OPEN_MODAL': { + return { + ...state, + displayModal: true, + displaySidebar: false, + } + } + case 'CLOSE_MODAL': { + return { + ...state, + displayModal: false, + } + } + case 'OPEN_TOAST': { + return { + ...state, + displayToast: true, + } + } + case 'CLOSE_TOAST': { + return { + ...state, + displayToast: false, + } + } + case 'SET_MODAL_VIEW': { + return { + ...state, + modalView: action.view, + } + } + case 'SET_TOAST_TEXT': { + return { + ...state, + toastText: action.text, + } + } + case 'SET_USER_AVATAR': { + return { + ...state, + userAvatar: action.value, + } + } + } +} + +export const UIProvider: FC = (props) => { + const [state, dispatch] = React.useReducer(uiReducer, initialState) + + const openSidebar = () => dispatch({ type: 'OPEN_SIDEBAR' }) + const closeSidebar = () => dispatch({ type: 'CLOSE_SIDEBAR' }) + const toggleSidebar = () => + state.displaySidebar + ? dispatch({ type: 'CLOSE_SIDEBAR' }) + : dispatch({ type: 'OPEN_SIDEBAR' }) + const closeSidebarIfPresent = () => + state.displaySidebar && dispatch({ type: 'CLOSE_SIDEBAR' }) + + const openDropdown = () => dispatch({ type: 'OPEN_DROPDOWN' }) + const closeDropdown = () => dispatch({ type: 'CLOSE_DROPDOWN' }) + + const openModal = () => dispatch({ type: 'OPEN_MODAL' }) + const closeModal = () => dispatch({ type: 'CLOSE_MODAL' }) + + const openToast = () => dispatch({ type: 'OPEN_TOAST' }) + const closeToast = () => dispatch({ type: 'CLOSE_TOAST' }) + + const setUserAvatar = (value: string) => + dispatch({ type: 'SET_USER_AVATAR', value }) + + const setModalView = (view: MODAL_VIEWS) => + dispatch({ type: 'SET_MODAL_VIEW', view }) + + const value = useMemo( + () => ({ + ...state, + openSidebar, + closeSidebar, + toggleSidebar, + closeSidebarIfPresent, + openDropdown, + closeDropdown, + openModal, + closeModal, + setModalView, + openToast, + closeToast, + setUserAvatar, + }), + [state] + ) + + return +} + +export const useUI = () => { + const context = React.useContext(UIContext) + if (context === undefined) { + throw new Error(`useUI must be used within a UIProvider`) + } + return context +} + +export const ManagedUIContext: FC = ({ children }) => ( + + {children} + +) diff --git a/components/ui/index.ts b/components/ui/index.ts new file mode 100644 index 00000000..f2a29320 --- /dev/null +++ b/components/ui/index.ts @@ -0,0 +1,13 @@ +export { default as Hero } from './Hero' +export { default as Logo } from './Logo' +export { default as Grid } from './Grid' +export { default as Button } from './Button' +export { default as Sidebar } from './Sidebar' +export { default as Marquee } from './Marquee' +export { default as Container } from './Container' +export { default as LoadingDots } from './LoadingDots' +export { default as Skeleton } from './Skeleton' +export { default as Modal } from './Modal' +export { default as Text } from './Text' +export { default as Input } from './Input' +export { useUI } from './context' diff --git a/components/wishlist/WishlistButton/WishlistButton.tsx b/components/wishlist/WishlistButton/WishlistButton.tsx new file mode 100644 index 00000000..6dc59b90 --- /dev/null +++ b/components/wishlist/WishlistButton/WishlistButton.tsx @@ -0,0 +1,78 @@ +import React, { FC, useState } from 'react' +import cn from 'classnames' +import { useUI } from '@components/ui' +import { Heart } from '@components/icons' +import useAddItem from '@framework/wishlist/use-add-item' +import useCustomer from '@framework/customer/use-customer' +import useWishlist from '@framework/wishlist/use-wishlist' +import useRemoveItem from '@framework/wishlist/use-remove-item' +import type { Product, ProductVariant } from '@commerce/types' + +type Props = { + productId: Product['id'] + variant: ProductVariant +} & React.ButtonHTMLAttributes + +const WishlistButton: FC = ({ + productId, + variant, + className, + ...props +}) => { + const { data } = useWishlist() + const addItem = useAddItem() + const removeItem = useRemoveItem() + const { data: customer } = useCustomer() + const { openModal, setModalView } = useUI() + const [loading, setLoading] = useState(false) + + // @ts-ignore Wishlist is not always enabled + const itemInWishlist = data?.items?.find( + // @ts-ignore Wishlist is not always enabled + (item) => + item.product_id === Number(productId) && + (item.variant_id as any) === Number(variant.id) + ) + + const handleWishlistChange = async (e: any) => { + e.preventDefault() + + if (loading) return + + // A login is required before adding an item to the wishlist + if (!customer) { + setModalView('LOGIN_VIEW') + return openModal() + } + + setLoading(true) + + try { + if (itemInWishlist) { + await removeItem({ id: itemInWishlist.id! }) + } else { + await addItem({ + productId, + variantId: variant?.id!, + }) + } + + setLoading(false) + } catch (err) { + setLoading(false) + } + } + + return ( + + ) +} + +export default WishlistButton diff --git a/components/wishlist/WishlistButton/index.ts b/components/wishlist/WishlistButton/index.ts new file mode 100644 index 00000000..66e88074 --- /dev/null +++ b/components/wishlist/WishlistButton/index.ts @@ -0,0 +1 @@ +export { default } from './WishlistButton' diff --git a/components/wishlist/WishlistCard/WishlistCard.module.css b/components/wishlist/WishlistCard/WishlistCard.module.css new file mode 100644 index 00000000..879184da --- /dev/null +++ b/components/wishlist/WishlistCard/WishlistCard.module.css @@ -0,0 +1,21 @@ +.root { + @apply grid grid-cols-12 w-full gap-6 px-3 py-6 border-b border-accents-2 transition duration-100 ease-in-out; + + &:nth-child(3n + 1) { + & .productBg { + @apply bg-violet; + } + } + + &:nth-child(3n + 2) { + & .productBg { + @apply bg-pink; + } + } + + &:nth-child(3n + 3) { + & .productBg { + @apply bg-blue; + } + } +} diff --git a/components/wishlist/WishlistCard/WishlistCard.tsx b/components/wishlist/WishlistCard/WishlistCard.tsx new file mode 100644 index 00000000..1568d9e7 --- /dev/null +++ b/components/wishlist/WishlistCard/WishlistCard.tsx @@ -0,0 +1,101 @@ +import { FC, useState } from 'react' +import cn from 'classnames' +import Link from 'next/link' +import Image from 'next/image' +import s from './WishlistCard.module.css' +import { Trash } from '@components/icons' +import { Button, Text } from '@components/ui' + +import { useUI } from '@components/ui/context' +import type { Product } from '@commerce/types' +import usePrice from '@framework/product/use-price' +import useAddItem from '@framework/cart/use-add-item' +import useRemoveItem from '@framework/wishlist/use-remove-item' + +interface Props { + product: Product +} + +const WishlistCard: FC = ({ product }) => { + const { price } = usePrice({ + amount: product.prices?.price?.value, + baseAmount: product.prices?.retailPrice?.value, + currencyCode: product.prices?.price?.currencyCode!, + }) + // @ts-ignore Wishlist is not always enabled + const removeItem = useRemoveItem({ wishlist: { includeProducts: true } }) + const [loading, setLoading] = useState(false) + const [removing, setRemoving] = useState(false) + const addItem = useAddItem() + const { openSidebar } = useUI() + + const handleRemove = async () => { + setRemoving(true) + + try { + // If this action succeeds then there's no need to do `setRemoving(true)` + // because the component will be removed from the view + await removeItem({ id: product.id! }) + } catch (error) { + setRemoving(false) + } + } + const addToCart = async () => { + setLoading(true) + try { + await addItem({ + productId: String(product.id), + variantId: String(product.variants[0].id), + }) + openSidebar() + setLoading(false) + } catch (err) { + setLoading(false) + } + } + + return ( +
    +
    + {product.images[0].alt +
    + +
    +

    + + {product.name} + +

    +
    + +
    + +
    +
    +
    {price}
    +
    + +
    +
    +
    + ) +} + +export default WishlistCard diff --git a/components/wishlist/WishlistCard/index.ts b/components/wishlist/WishlistCard/index.ts new file mode 100644 index 00000000..ef572805 --- /dev/null +++ b/components/wishlist/WishlistCard/index.ts @@ -0,0 +1 @@ +export { default } from './WishlistCard' diff --git a/components/wishlist/index.ts b/components/wishlist/index.ts new file mode 100644 index 00000000..8aee9f81 --- /dev/null +++ b/components/wishlist/index.ts @@ -0,0 +1,2 @@ +export { default as WishlistCard } from './WishlistCard' +export { default as WishlistButton } from './WishlistButton' diff --git a/config/seo.json b/config/seo.json new file mode 100644 index 00000000..82520cf9 --- /dev/null +++ b/config/seo.json @@ -0,0 +1,26 @@ +{ + "title": "ACME Storefront | Powered by Next.js Commerce", + "titleTemplate": "%s - ACME Storefront", + "description": "Next.js Commerce - https://www.nextjs.org/commerce", + "openGraph": { + "title": "ACME Storefront | Powered by Next.js Commerce", + "description": "Next.js Commerce - https://www.nextjs.org/commerce", + "type": "website", + "locale": "en_IE", + "url": "https://nextjs.org/commerce", + "site_name": "Next.js Commerce", + "images": [ + { + "url": "/card.png", + "width": 800, + "height": 600, + "alt": "Next.js Commerce" + } + ] + }, + "twitter": { + "handle": "@nextjs", + "site": "@nextjs", + "cardType": "summary_large_image" + } +} diff --git a/framework/bigcommerce/.env.template b/framework/bigcommerce/.env.template new file mode 100644 index 00000000..2b91bc09 --- /dev/null +++ b/framework/bigcommerce/.env.template @@ -0,0 +1,8 @@ +COMMERCE_PROVIDER=bigcommerce + +BIGCOMMERCE_STOREFRONT_API_URL= +BIGCOMMERCE_STOREFRONT_API_TOKEN= +BIGCOMMERCE_STORE_API_URL= +BIGCOMMERCE_STORE_API_TOKEN= +BIGCOMMERCE_STORE_API_CLIENT_ID= +BIGCOMMERCE_CHANNEL_ID= diff --git a/framework/bigcommerce/README.md b/framework/bigcommerce/README.md new file mode 100644 index 00000000..7f62a5f3 --- /dev/null +++ b/framework/bigcommerce/README.md @@ -0,0 +1,59 @@ +# Bigcommerce Provider + +**Demo:** https://bigcommerce.demo.vercel.store/ + +With the deploy button below you'll be able to have a [BigCommerce](https://www.bigcommerce.com/) account and a store that works with this starter: + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-description=An%20all-in-one%20starter%20kit%20for%20high-performance%20e-commerce%20sites.&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&integration-ids=oac_MuWZiE4jtmQ2ejZQaQ7ncuDT) + +If you already have a BigCommerce account and want to use your current store, then copy the `.env.template` file in this directory to `.env.local` in the main directory (which will be ignored by Git): + +```bash +cp framework/bigcommerce/.env.template .env.local +``` + +Then, set the environment variables in `.env.local` to match the ones from your store. + +## Contribute + +Our commitment to Open Source can be found [here](https://vercel.com/oss). + +If you find an issue with the provider or want a new feature, feel free to open a PR or [create a new issue](https://github.com/vercel/commerce/issues). + +## Troubleshoot + +
    +I already own a BigCommerce store. What should I do? +
    +First thing you do is: set your environment variables +
    +
    +.env.local + +```sh +BIGCOMMERCE_STOREFRONT_API_URL=<> +BIGCOMMERCE_STOREFRONT_API_TOKEN=<> +BIGCOMMERCE_STORE_API_URL=<> +BIGCOMMERCE_STORE_API_TOKEN=<> +BIGCOMMERCE_STORE_API_CLIENT_ID=<> +BIGCOMMERCE_CHANNEL_ID=<> +``` + +If your project was started with a "Deploy with Vercel" button, you can use Vercel's CLI to retrieve these credentials. + +1. Install Vercel CLI: `npm i -g vercel` +2. Link local instance with Vercel and Github accounts (creates .vercel file): `vercel link` +3. Download your environment variables: `vercel env pull .env.local` + +Next, you're free to customize the starter. More updates coming soon. Stay tuned. + +
    + +
    +BigCommerce shows a Coming Soon page and requests a Preview Code +
    +After Email confirmation, Checkout should be manually enabled through BigCommerce platform. Look for "Review & test your store" section through BigCommerce's dashboard. +
    +
    +BigCommerce team has been notified and they plan to add more detailed about this subject. +
    diff --git a/framework/bigcommerce/api/cart/handlers/add-item.ts b/framework/bigcommerce/api/cart/handlers/add-item.ts new file mode 100644 index 00000000..c47e72cd --- /dev/null +++ b/framework/bigcommerce/api/cart/handlers/add-item.ts @@ -0,0 +1,45 @@ +import { parseCartItem } from '../../utils/parse-item' +import getCartCookie from '../../utils/get-cart-cookie' +import type { CartHandlers } from '..' + +const addItem: CartHandlers['addItem'] = async ({ + res, + body: { cartId, item }, + config, +}) => { + if (!item) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Missing item' }], + }) + } + if (!item.quantity) item.quantity = 1 + + const options = { + method: 'POST', + body: JSON.stringify({ + line_items: [parseCartItem(item)], + ...(!cartId && config.storeChannelId + ? { channel_id: config.storeChannelId } + : {}), + }), + } + const { data } = cartId + ? await config.storeApiFetch( + `/v3/carts/${cartId}/items?include=line_items.physical_items.options`, + options + ) + : await config.storeApiFetch( + '/v3/carts?include=line_items.physical_items.options', + options + ) + + // Create or update the cart cookie + res.setHeader( + 'Set-Cookie', + getCartCookie(config.cartCookie, data.id, config.cartCookieMaxAge) + ) + res.status(200).json({ data }) +} + +export default addItem diff --git a/framework/bigcommerce/api/cart/handlers/get-cart.ts b/framework/bigcommerce/api/cart/handlers/get-cart.ts new file mode 100644 index 00000000..890ac999 --- /dev/null +++ b/framework/bigcommerce/api/cart/handlers/get-cart.ts @@ -0,0 +1,32 @@ +import type { BigcommerceCart } from '../../../types' +import { BigcommerceApiError } from '../../utils/errors' +import getCartCookie from '../../utils/get-cart-cookie' +import type { CartHandlers } from '../' + +// Return current cart info +const getCart: CartHandlers['getCart'] = async ({ + res, + body: { cartId }, + config, +}) => { + let result: { data?: BigcommerceCart } = {} + + if (cartId) { + try { + result = await config.storeApiFetch( + `/v3/carts/${cartId}?include=line_items.physical_items.options` + ) + } catch (error) { + if (error instanceof BigcommerceApiError && error.status === 404) { + // Remove the cookie if it exists but the cart wasn't found + res.setHeader('Set-Cookie', getCartCookie(config.cartCookie)) + } else { + throw error + } + } + } + + res.status(200).json({ data: result.data ?? null }) +} + +export default getCart diff --git a/framework/bigcommerce/api/cart/handlers/remove-item.ts b/framework/bigcommerce/api/cart/handlers/remove-item.ts new file mode 100644 index 00000000..c0984894 --- /dev/null +++ b/framework/bigcommerce/api/cart/handlers/remove-item.ts @@ -0,0 +1,33 @@ +import getCartCookie from '../../utils/get-cart-cookie' +import type { CartHandlers } from '..' + +const removeItem: CartHandlers['removeItem'] = async ({ + res, + body: { cartId, itemId }, + config, +}) => { + if (!cartId || !itemId) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const result = await config.storeApiFetch<{ data: any } | null>( + `/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`, + { method: 'DELETE' } + ) + const data = result?.data ?? null + + res.setHeader( + 'Set-Cookie', + data + ? // Update the cart cookie + getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge) + : // Remove the cart cookie if the cart was removed (empty items) + getCartCookie(config.cartCookie) + ) + res.status(200).json({ data }) +} + +export default removeItem diff --git a/framework/bigcommerce/api/cart/handlers/update-item.ts b/framework/bigcommerce/api/cart/handlers/update-item.ts new file mode 100644 index 00000000..27b74ca2 --- /dev/null +++ b/framework/bigcommerce/api/cart/handlers/update-item.ts @@ -0,0 +1,35 @@ +import { parseCartItem } from '../../utils/parse-item' +import getCartCookie from '../../utils/get-cart-cookie' +import type { CartHandlers } from '..' + +const updateItem: CartHandlers['updateItem'] = async ({ + res, + body: { cartId, itemId, item }, + config, +}) => { + if (!cartId || !itemId || !item) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const { data } = await config.storeApiFetch( + `/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`, + { + method: 'PUT', + body: JSON.stringify({ + line_item: parseCartItem(item), + }), + } + ) + + // Update the cart cookie + res.setHeader( + 'Set-Cookie', + getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge) + ) + res.status(200).json({ data }) +} + +export default updateItem diff --git a/framework/bigcommerce/api/cart/index.ts b/framework/bigcommerce/api/cart/index.ts new file mode 100644 index 00000000..4ee66889 --- /dev/null +++ b/framework/bigcommerce/api/cart/index.ts @@ -0,0 +1,78 @@ +import isAllowedMethod from '../utils/is-allowed-method' +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import { BigcommerceApiError } from '../utils/errors' +import getCart from './handlers/get-cart' +import addItem from './handlers/add-item' +import updateItem from './handlers/update-item' +import removeItem from './handlers/remove-item' +import type { + BigcommerceCart, + GetCartHandlerBody, + AddCartItemHandlerBody, + UpdateCartItemHandlerBody, + RemoveCartItemHandlerBody, +} from '../../types' + +export type CartHandlers = { + getCart: BigcommerceHandler + addItem: BigcommerceHandler + updateItem: BigcommerceHandler + removeItem: BigcommerceHandler +} + +const METHODS = ['GET', 'POST', 'PUT', 'DELETE'] + +// TODO: a complete implementation should have schema validation for `req.body` +const cartApi: BigcommerceApiHandler = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + const { cookies } = req + const cartId = cookies[config.cartCookie] + + try { + // Return current cart info + if (req.method === 'GET') { + const body = { cartId } + return await handlers['getCart']({ req, res, config, body }) + } + + // Create or add an item to the cart + if (req.method === 'POST') { + const body = { ...req.body, cartId } + return await handlers['addItem']({ req, res, config, body }) + } + + // Update item in cart + if (req.method === 'PUT') { + const body = { ...req.body, cartId } + return await handlers['updateItem']({ req, res, config, body }) + } + + // Remove an item from the cart + if (req.method === 'DELETE') { + const body = { ...req.body, cartId } + return await handlers['removeItem']({ req, res, config, body }) + } + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +export const handlers = { getCart, addItem, updateItem, removeItem } + +export default createApiHandler(cartApi, handlers, {}) diff --git a/framework/bigcommerce/api/catalog/handlers/get-products.ts b/framework/bigcommerce/api/catalog/handlers/get-products.ts new file mode 100644 index 00000000..bedd773b --- /dev/null +++ b/framework/bigcommerce/api/catalog/handlers/get-products.ts @@ -0,0 +1,79 @@ +import { Product } from '@commerce/types' +import getAllProducts, { ProductEdge } from '../../../product/get-all-products' +import type { ProductsHandlers } from '../products' + +const SORT: { [key: string]: string | undefined } = { + latest: 'id', + trending: 'total_sold', + price: 'price', +} + +const LIMIT = 12 + +// Return current cart info +const getProducts: ProductsHandlers['getProducts'] = async ({ + res, + body: { search, category, brand, sort }, + config, +}) => { + // Use a dummy base as we only care about the relative path + const url = new URL('/v3/catalog/products', 'http://a') + + url.searchParams.set('is_visible', 'true') + url.searchParams.set('limit', String(LIMIT)) + + if (search) url.searchParams.set('keyword', search) + + if (category && Number.isInteger(Number(category))) + url.searchParams.set('categories:in', category) + + if (brand && Number.isInteger(Number(brand))) + url.searchParams.set('brand_id', brand) + + if (sort) { + const [_sort, direction] = sort.split('-') + const sortValue = SORT[_sort] + + if (sortValue && direction) { + url.searchParams.set('sort', sortValue) + url.searchParams.set('direction', direction) + } + } + + // We only want the id of each product + url.searchParams.set('include_fields', 'id') + + const { data } = await config.storeApiFetch<{ data: { id: number }[] }>( + url.pathname + url.search + ) + + const entityIds = data.map((p) => p.id) + const found = entityIds.length > 0 + + // We want the GraphQL version of each product + const graphqlData = await getAllProducts({ + variables: { first: LIMIT, entityIds }, + config, + }) + + // Put the products in an object that we can use to get them by id + const productsById = graphqlData.products.reduce<{ + [k: number]: Product + }>((prods, p) => { + prods[Number(p.id)] = p + return prods + }, {}) + + const products: Product[] = found ? [] : graphqlData.products + + // Populate the products array with the graphql products, in the order + // assigned by the list of entity ids + entityIds.forEach((id) => { + const product = productsById[id] + if (product) products.push(product) + }) + + res.status(200).json({ data: { products, found } }) +} + +export default getProducts diff --git a/framework/bigcommerce/api/catalog/products.ts b/framework/bigcommerce/api/catalog/products.ts new file mode 100644 index 00000000..d52b2de7 --- /dev/null +++ b/framework/bigcommerce/api/catalog/products.ts @@ -0,0 +1,48 @@ +import type { Product } from '@commerce/types' +import isAllowedMethod from '../utils/is-allowed-method' +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import { BigcommerceApiError } from '../utils/errors' +import getProducts from './handlers/get-products' + +export type SearchProductsData = { + products: Product[] + found: boolean +} + +export type ProductsHandlers = { + getProducts: BigcommerceHandler< + SearchProductsData, + { search?: string; category?: string; brand?: string; sort?: string } + > +} + +const METHODS = ['GET'] + +// TODO(lf): a complete implementation should have schema validation for `req.body` +const productsApi: BigcommerceApiHandler< + SearchProductsData, + ProductsHandlers +> = async (req, res, config, handlers) => { + if (!isAllowedMethod(req, res, METHODS)) return + + try { + const body = req.query + return await handlers['getProducts']({ req, res, config, body }) + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +export const handlers = { getProducts } + +export default createApiHandler(productsApi, handlers, {}) diff --git a/framework/bigcommerce/api/checkout.ts b/framework/bigcommerce/api/checkout.ts new file mode 100644 index 00000000..530f4c40 --- /dev/null +++ b/framework/bigcommerce/api/checkout.ts @@ -0,0 +1,77 @@ +import isAllowedMethod from './utils/is-allowed-method' +import createApiHandler, { + BigcommerceApiHandler, +} from './utils/create-api-handler' +import { BigcommerceApiError } from './utils/errors' + +const METHODS = ['GET'] +const fullCheckout = true + +// TODO: a complete implementation should have schema validation for `req.body` +const checkoutApi: BigcommerceApiHandler = async (req, res, config) => { + if (!isAllowedMethod(req, res, METHODS)) return + + const { cookies } = req + const cartId = cookies[config.cartCookie] + + try { + if (!cartId) { + res.redirect('/cart') + return + } + + const { data } = await config.storeApiFetch( + `/v3/carts/${cartId}/redirect_urls`, + { + method: 'POST', + } + ) + + if (fullCheckout) { + res.redirect(data.checkout_url) + return + } + + // TODO: make the embedded checkout work too! + const html = ` + + + + + + Checkout + + + + +
    + + + ` + + res.status(200) + res.setHeader('Content-Type', 'text/html') + res.write(html) + res.end() + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +export default createApiHandler(checkoutApi, {}, {}) diff --git a/framework/bigcommerce/api/customers/handlers/get-logged-in-customer.ts b/framework/bigcommerce/api/customers/handlers/get-logged-in-customer.ts new file mode 100644 index 00000000..698235dd --- /dev/null +++ b/framework/bigcommerce/api/customers/handlers/get-logged-in-customer.ts @@ -0,0 +1,59 @@ +import type { GetLoggedInCustomerQuery } from '../../../schema' +import type { CustomersHandlers } from '..' + +export const getLoggedInCustomerQuery = /* GraphQL */ ` + query getLoggedInCustomer { + customer { + entityId + firstName + lastName + email + company + customerGroupId + notes + phone + addressCount + attributeCount + storeCredit { + value + currencyCode + } + } + } +` + +export type Customer = NonNullable + +const getLoggedInCustomer: CustomersHandlers['getLoggedInCustomer'] = async ({ + req, + res, + config, +}) => { + const token = req.cookies[config.customerCookie] + + if (token) { + const { data } = await config.fetch( + getLoggedInCustomerQuery, + undefined, + { + headers: { + cookie: `${config.customerCookie}=${token}`, + }, + } + ) + const { customer } = data + + if (!customer) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Customer not found', code: 'not_found' }], + }) + } + + return res.status(200).json({ data: { customer } }) + } + + res.status(200).json({ data: null }) +} + +export default getLoggedInCustomer diff --git a/framework/bigcommerce/api/customers/handlers/login.ts b/framework/bigcommerce/api/customers/handlers/login.ts new file mode 100644 index 00000000..9e019f3a --- /dev/null +++ b/framework/bigcommerce/api/customers/handlers/login.ts @@ -0,0 +1,49 @@ +import { FetcherError } from '@commerce/utils/errors' +import login from '../../../auth/login' +import type { LoginHandlers } from '../login' + +const invalidCredentials = /invalid credentials/i + +const loginHandler: LoginHandlers['login'] = async ({ + res, + body: { email, password }, + config, +}) => { + // TODO: Add proper validations with something like Ajv + if (!(email && password)) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + // TODO: validate the password and email + // Passwords must be at least 7 characters and contain both alphabetic + // and numeric characters. + + try { + await login({ variables: { email, password }, config, res }) + } catch (error) { + // Check if the email and password didn't match an existing account + if ( + error instanceof FetcherError && + invalidCredentials.test(error.message) + ) { + return res.status(401).json({ + data: null, + errors: [ + { + message: + 'Cannot find an account that matches the provided credentials', + code: 'invalid_credentials', + }, + ], + }) + } + + throw error + } + + res.status(200).json({ data: null }) +} + +export default loginHandler diff --git a/framework/bigcommerce/api/customers/handlers/logout.ts b/framework/bigcommerce/api/customers/handlers/logout.ts new file mode 100644 index 00000000..937ce095 --- /dev/null +++ b/framework/bigcommerce/api/customers/handlers/logout.ts @@ -0,0 +1,23 @@ +import { serialize } from 'cookie' +import { LogoutHandlers } from '../logout' + +const logoutHandler: LogoutHandlers['logout'] = async ({ + res, + body: { redirectTo }, + config, +}) => { + // Remove the cookie + res.setHeader( + 'Set-Cookie', + serialize(config.customerCookie, '', { maxAge: -1, path: '/' }) + ) + + // Only allow redirects to a relative URL + if (redirectTo?.startsWith('/')) { + res.redirect(redirectTo) + } else { + res.status(200).json({ data: null }) + } +} + +export default logoutHandler diff --git a/framework/bigcommerce/api/customers/handlers/signup.ts b/framework/bigcommerce/api/customers/handlers/signup.ts new file mode 100644 index 00000000..1b24db0c --- /dev/null +++ b/framework/bigcommerce/api/customers/handlers/signup.ts @@ -0,0 +1,62 @@ +import { BigcommerceApiError } from '../../utils/errors' +import login from '../../../auth/login' +import { SignupHandlers } from '../signup' + +const signup: SignupHandlers['signup'] = async ({ + res, + body: { firstName, lastName, email, password }, + config, +}) => { + // TODO: Add proper validations with something like Ajv + if (!(firstName && lastName && email && password)) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + // TODO: validate the password and email + // Passwords must be at least 7 characters and contain both alphabetic + // and numeric characters. + + try { + await config.storeApiFetch('/v3/customers', { + method: 'POST', + body: JSON.stringify([ + { + first_name: firstName, + last_name: lastName, + email, + authentication: { + new_password: password, + }, + }, + ]), + }) + } catch (error) { + if (error instanceof BigcommerceApiError && error.status === 422) { + const hasEmailError = '0.email' in error.data?.errors + + // If there's an error with the email, it most likely means it's duplicated + if (hasEmailError) { + return res.status(400).json({ + data: null, + errors: [ + { + message: 'The email is already in use', + code: 'duplicated_email', + }, + ], + }) + } + } + + throw error + } + + // Login the customer right after creating it + await login({ variables: { email, password }, res, config }) + + res.status(200).json({ data: null }) +} + +export default signup diff --git a/framework/bigcommerce/api/customers/index.ts b/framework/bigcommerce/api/customers/index.ts new file mode 100644 index 00000000..5af4d1d1 --- /dev/null +++ b/framework/bigcommerce/api/customers/index.ts @@ -0,0 +1,46 @@ +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import isAllowedMethod from '../utils/is-allowed-method' +import { BigcommerceApiError } from '../utils/errors' +import getLoggedInCustomer, { + Customer, +} from './handlers/get-logged-in-customer' + +export type { Customer } + +export type CustomerData = { + customer: Customer +} + +export type CustomersHandlers = { + getLoggedInCustomer: BigcommerceHandler +} + +const METHODS = ['GET'] + +const customersApi: BigcommerceApiHandler< + CustomerData, + CustomersHandlers +> = async (req, res, config, handlers) => { + if (!isAllowedMethod(req, res, METHODS)) return + + try { + const body = null + return await handlers['getLoggedInCustomer']({ req, res, config, body }) + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +const handlers = { getLoggedInCustomer } + +export default createApiHandler(customersApi, handlers, {}) diff --git a/framework/bigcommerce/api/customers/login.ts b/framework/bigcommerce/api/customers/login.ts new file mode 100644 index 00000000..e8f24a92 --- /dev/null +++ b/framework/bigcommerce/api/customers/login.ts @@ -0,0 +1,45 @@ +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import isAllowedMethod from '../utils/is-allowed-method' +import { BigcommerceApiError } from '../utils/errors' +import login from './handlers/login' + +export type LoginBody = { + email: string + password: string +} + +export type LoginHandlers = { + login: BigcommerceHandler> +} + +const METHODS = ['POST'] + +const loginApi: BigcommerceApiHandler = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + try { + const body = req.body ?? {} + return await handlers['login']({ req, res, config, body }) + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +const handlers = { login } + +export default createApiHandler(loginApi, handlers, {}) diff --git a/framework/bigcommerce/api/customers/logout.ts b/framework/bigcommerce/api/customers/logout.ts new file mode 100644 index 00000000..0a496524 --- /dev/null +++ b/framework/bigcommerce/api/customers/logout.ts @@ -0,0 +1,42 @@ +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import isAllowedMethod from '../utils/is-allowed-method' +import { BigcommerceApiError } from '../utils/errors' +import logout from './handlers/logout' + +export type LogoutHandlers = { + logout: BigcommerceHandler +} + +const METHODS = ['GET'] + +const logoutApi: BigcommerceApiHandler = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + try { + const redirectTo = req.query.redirect_to + const body = typeof redirectTo === 'string' ? { redirectTo } : {} + + return await handlers['logout']({ req, res, config, body }) + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +const handlers = { logout } + +export default createApiHandler(logoutApi, handlers, {}) diff --git a/framework/bigcommerce/api/customers/signup.ts b/framework/bigcommerce/api/customers/signup.ts new file mode 100644 index 00000000..aa26f78c --- /dev/null +++ b/framework/bigcommerce/api/customers/signup.ts @@ -0,0 +1,50 @@ +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import isAllowedMethod from '../utils/is-allowed-method' +import { BigcommerceApiError } from '../utils/errors' +import signup from './handlers/signup' + +export type SignupBody = { + firstName: string + lastName: string + email: string + password: string +} + +export type SignupHandlers = { + signup: BigcommerceHandler> +} + +const METHODS = ['POST'] + +const signupApi: BigcommerceApiHandler = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + const { cookies } = req + const cartId = cookies[config.cartCookie] + + try { + const body = { ...req.body, cartId } + return await handlers['signup']({ req, res, config, body }) + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +const handlers = { signup } + +export default createApiHandler(signupApi, handlers, {}) diff --git a/framework/bigcommerce/api/definitions/catalog.ts b/framework/bigcommerce/api/definitions/catalog.ts new file mode 100644 index 00000000..2c483f78 --- /dev/null +++ b/framework/bigcommerce/api/definitions/catalog.ts @@ -0,0 +1,2993 @@ +/** + * This file was auto-generated by swagger-to-ts. + * Do not make direct changes to the file. + */ + +export interface definitions { + /** + * Common Modifier properties. + */ + productModifier_Base: { + /** + * BigCommerce API, which determines how it will display on the storefront. Acceptable values: `date`, `checkbox`, `file`, `text`, `multi_line_text`, `numbers_only_text`, `radio_buttons`, `rectangles`, `dropdown`, `product_list`, `product_list_with_images`, `swatch`. Required in a /POST. + */ + type: + | 'date' + | 'checkbox' + | 'file' + | 'text' + | 'multi_line_text' + | 'numbers_only_text' + | 'radio_buttons' + | 'rectangles' + | 'dropdown' + | 'product_list' + | 'product_list_with_images' + | 'swatch' + /** + * Whether or not this modifer is required or not at checkout. Required in a /POST. + */ + required: boolean + /** + * The order the modifiers display on the product detail page. + */ + sort_order?: number + config?: definitions['config_Full'] + /** + * The name of the option shown on the storefront. + */ + display_name?: string + } + /** + * Product Modifier + */ + productModifier_Full: definitions['productModifier_Base'] & { + /** + * The unique numeric ID of the modifier; increments sequentially. + */ + id?: number + /** + * The unique numeric ID of the product to which the option belongs. + */ + product_id?: number + /** + * The unique option name. Auto-generated from the display name, a timestamp, and the product ID. + */ + name?: string + option_values?: definitions['productModifierOptionValue_Full'][] + } + /** + * The model for a POST to create a modifier on a product. + */ + productModifier_Post: { + /** + * BigCommerce API, which determines how it will display on the storefront. Acceptable values: `date`, `checkbox`, `file`, `text`, `multi_line_text`, `numbers_only_text`, `radio_buttons`, `rectangles`, `dropdown`, `product_list`, `product_list_with_images`, `swatch`. Required in a /POST. + */ + type: + | 'date' + | 'checkbox' + | 'file' + | 'text' + | 'multi_line_text' + | 'numbers_only_text' + | 'radio_buttons' + | 'rectangles' + | 'dropdown' + | 'product_list' + | 'product_list_with_images' + | 'swatch' + /** + * Whether or not this modifer is required or not at checkout. Required in a /POST. + */ + required: boolean + /** + * The order the modifiers display on the product detail page. + */ + sort_order?: number + /** + * The values for option config can vary based on the Modifier created. + */ + config?: { + /** + * (date, text, multi_line_text, numbers_only_text) The default value. Shown on a date option as an ISO-8601–formatted string, or on a text option as a string. + */ + default_value?: string + /** + * (checkbox) Flag for setting the checkbox to be checked by default. + */ + checked_by_default?: boolean + /** + * (checkbox) Label displayed for the checkbox option. + */ + checkbox_label?: string + /** + * (date) Flag to limit the dates allowed to be entered on a date option. + */ + date_limited?: boolean + /** + * (date) The type of limit that is allowed to be entered on a date option. + */ + date_limit_mode?: 'earliest' | 'range' | 'latest' + /** + * (date) The earliest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_earliest_value?: string + /** + * (date) The latest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_latest_value?: string + /** + * (file) The kind of restriction on the file types that can be uploaded with a file upload option. Values: `specific` - restricts uploads to particular file types; `all` - allows all file types. + */ + file_types_mode?: 'specific' | 'all' + /** + * (file) The type of files allowed to be uploaded if the `file_type_option` is set to `specific`. Values: + * `images` - Allows upload of image MIME types (`bmp`, `gif`, `jpg`, `jpeg`, `jpe`, `jif`, `jfif`, `jfi`, `png`, `wbmp`, `xbm`, `tiff`). `documents` - Allows upload of document MIME types (`txt`, `pdf`, `rtf`, `doc`, `docx`, `xls`, `xlsx`, `accdb`, `mdb`, `one`, `pps`, `ppsx`, `ppt`, `pptx`, `pub`, `odt`, `ods`, `odp`, `odg`, `odf`). + * `other` - Allows file types defined in the `file_types_other` array. + */ + file_types_supported?: string[] + /** + * (file) A list of other file types allowed with the file upload option. + */ + file_types_other?: string[] + /** + * (file) The maximum size for a file that can be used with the file upload option. This will still be limited by the server. + */ + file_max_size?: number + /** + * (text, multi_line_text) Flag to validate the length of a text or multi-line text input. + */ + text_characters_limited?: boolean + /** + * (text, multi_line_text) The minimum length allowed for a text or multi-line text option. + */ + text_min_length?: number + /** + * (text, multi_line_text) The maximum length allowed for a text or multi line text option. + */ + text_max_length?: number + /** + * (multi_line_text) Flag to validate the maximum number of lines allowed on a multi-line text input. + */ + text_lines_limited?: boolean + /** + * (multi_line_text) The maximum number of lines allowed on a multi-line text input. + */ + text_max_lines?: number + /** + * (numbers_only_text) Flag to limit the value of a number option. + */ + number_limited?: boolean + /** + * (numbers_only_text) The type of limit on values entered for a number option. + */ + number_limit_mode?: 'lowest' | 'highest' | 'range' + /** + * (numbers_only_text) The lowest allowed value for a number option if `number_limited` is true. + */ + number_lowest_value?: number + /** + * (numbers_only_text) The highest allowed value for a number option if `number_limited` is true. + */ + number_highest_value?: number + /** + * (numbers_only_text) Flag to limit the input on a number option to whole numbers only. + */ + number_integers_only?: boolean + /** + * (product_list, product_list_with_images) Flag for automatically adjusting inventory on a product included in the list. + */ + product_list_adjusts_inventory?: boolean + /** + * (product_list, product_list_with_images) Flag to add the optional product's price to the main product's price. + */ + product_list_adjusts_pricing?: boolean + /** + * (product_list, product_list_with_images) How to factor the optional product's weight and package dimensions into the shipping quote. Values: `none` - don't adjust; `weight` - use shipping weight only; `package` - use weight and dimensions. + */ + product_list_shipping_calc?: 'none' | 'weight' | 'package' + } + option_values?: (({ + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. + */ + value_data?: { [key: string]: any } + } & { + adjusters?: { + /** + * Adjuster for Complex Rules. + */ + price?: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * Adjuster for Complex Rules. + */ + weight?: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * The URL for an image displayed on the storefront when the modifier value is selected.Limit of 8MB per file. + */ + image_url?: string + purchasing_disabled?: { + /** + * Flag for whether the modifier value disables purchasing when selected on the storefront. This can be used for temporarily disabling a particular modifier value. + */ + status?: boolean + /** + * The message displayed on the storefront when the purchasing disabled status is `true`. + */ + message?: string + } + } + }) & { + /** + * The unique numeric ID of the value; increments sequentially. + */ + id?: number + })[] + } & { + /** + * The name of the option shown on the storefront. + */ + display_name: string + } + /** + * The model for a PUT to update a modifier on a product. + */ + productModifier_Put: { + /** + * BigCommerce API, which determines how it will display on the storefront. Acceptable values: `date`, `checkbox`, `file`, `text`, `multi_line_text`, `numbers_only_text`, `radio_buttons`, `rectangles`, `dropdown`, `product_list`, `product_list_with_images`, `swatch`. Required in a /POST. + */ + type: + | 'date' + | 'checkbox' + | 'file' + | 'text' + | 'multi_line_text' + | 'numbers_only_text' + | 'radio_buttons' + | 'rectangles' + | 'dropdown' + | 'product_list' + | 'product_list_with_images' + | 'swatch' + /** + * Whether or not this modifer is required or not at checkout. Required in a /POST. + */ + required: boolean + /** + * The order the modifiers display on the product detail page. + */ + sort_order?: number + /** + * The values for option config can vary based on the Modifier created. + */ + config?: { + /** + * (date, text, multi_line_text, numbers_only_text) The default value. Shown on a date option as an ISO-8601–formatted string, or on a text option as a string. + */ + default_value?: string + /** + * (checkbox) Flag for setting the checkbox to be checked by default. + */ + checked_by_default?: boolean + /** + * (checkbox) Label displayed for the checkbox option. + */ + checkbox_label?: string + /** + * (date) Flag to limit the dates allowed to be entered on a date option. + */ + date_limited?: boolean + /** + * (date) The type of limit that is allowed to be entered on a date option. + */ + date_limit_mode?: 'earliest' | 'range' | 'latest' + /** + * (date) The earliest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_earliest_value?: string + /** + * (date) The latest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_latest_value?: string + /** + * (file) The kind of restriction on the file types that can be uploaded with a file upload option. Values: `specific` - restricts uploads to particular file types; `all` - allows all file types. + */ + file_types_mode?: 'specific' | 'all' + /** + * (file) The type of files allowed to be uploaded if the `file_type_option` is set to `specific`. Values: + * `images` - Allows upload of image MIME types (`bmp`, `gif`, `jpg`, `jpeg`, `jpe`, `jif`, `jfif`, `jfi`, `png`, `wbmp`, `xbm`, `tiff`). `documents` - Allows upload of document MIME types (`txt`, `pdf`, `rtf`, `doc`, `docx`, `xls`, `xlsx`, `accdb`, `mdb`, `one`, `pps`, `ppsx`, `ppt`, `pptx`, `pub`, `odt`, `ods`, `odp`, `odg`, `odf`). + * `other` - Allows file types defined in the `file_types_other` array. + */ + file_types_supported?: string[] + /** + * (file) A list of other file types allowed with the file upload option. + */ + file_types_other?: string[] + /** + * (file) The maximum size for a file that can be used with the file upload option. This will still be limited by the server. + */ + file_max_size?: number + /** + * (text, multi_line_text) Flag to validate the length of a text or multi-line text input. + */ + text_characters_limited?: boolean + /** + * (text, multi_line_text) The minimum length allowed for a text or multi-line text option. + */ + text_min_length?: number + /** + * (text, multi_line_text) The maximum length allowed for a text or multi line text option. + */ + text_max_length?: number + /** + * (multi_line_text) Flag to validate the maximum number of lines allowed on a multi-line text input. + */ + text_lines_limited?: boolean + /** + * (multi_line_text) The maximum number of lines allowed on a multi-line text input. + */ + text_max_lines?: number + /** + * (numbers_only_text) Flag to limit the value of a number option. + */ + number_limited?: boolean + /** + * (numbers_only_text) The type of limit on values entered for a number option. + */ + number_limit_mode?: 'lowest' | 'highest' | 'range' + /** + * (numbers_only_text) The lowest allowed value for a number option if `number_limited` is true. + */ + number_lowest_value?: number + /** + * (numbers_only_text) The highest allowed value for a number option if `number_limited` is true. + */ + number_highest_value?: number + /** + * (numbers_only_text) Flag to limit the input on a number option to whole numbers only. + */ + number_integers_only?: boolean + /** + * (product_list, product_list_with_images) Flag for automatically adjusting inventory on a product included in the list. + */ + product_list_adjusts_inventory?: boolean + /** + * (product_list, product_list_with_images) Flag to add the optional product's price to the main product's price. + */ + product_list_adjusts_pricing?: boolean + /** + * (product_list, product_list_with_images) How to factor the optional product's weight and package dimensions into the shipping quote. Values: `none` - don't adjust; `weight` - use shipping weight only; `package` - use weight and dimensions. + */ + product_list_shipping_calc?: 'none' | 'weight' | 'package' + } + option_values?: (({ + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. + */ + value_data?: { [key: string]: any } + } & { + adjusters?: { + /** + * Adjuster for Complex Rules. + */ + price?: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * Adjuster for Complex Rules. + */ + weight?: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * The URL for an image displayed on the storefront when the modifier value is selected.Limit of 8MB per file. + */ + image_url?: string + purchasing_disabled?: { + /** + * Flag for whether the modifier value disables purchasing when selected on the storefront. This can be used for temporarily disabling a particular modifier value. + */ + status?: boolean + /** + * The message displayed on the storefront when the purchasing disabled status is `true`. + */ + message?: string + } + } + }) & { + /** + * The unique numeric ID of the value; increments sequentially. + */ + id?: number + })[] + } + /** + * Common Product Modifer `option_value` properties. + */ + productModifierOptionValue_Base: { + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. If no data is available, returns `null`. + */ + value_data?: { [key: string]: any } + adjusters?: definitions['adjusters_Full'] + } + /** + * Product Modifer `option_value`. + */ + productModifierOptionValue_Full: definitions['productModifierOptionValue_Base'] & { + /** + * The unique numeric ID of the value; increments sequentially. + */ + id?: number + option_id?: number + } + /** + * The model for a POST to create a modifier value on a product. + */ + productModifierOptionValue_Post: { + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. + */ + value_data?: { [key: string]: any } + } & { + adjusters?: { + /** + * Adjuster for Complex Rules. + */ + price?: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * Adjuster for Complex Rules. + */ + weight?: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * The URL for an image displayed on the storefront when the modifier value is selected.Limit of 8MB per file. + */ + image_url?: string + purchasing_disabled?: { + /** + * Flag for whether the modifier value disables purchasing when selected on the storefront. This can be used for temporarily disabling a particular modifier value. + */ + status?: boolean + /** + * The message displayed on the storefront when the purchasing disabled status is `true`. + */ + message?: string + } + } + } + /** + * The model for a PUT to update a modifier value on a product. + */ + productModifierOptionValue_Put: ({ + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. + */ + value_data?: { [key: string]: any } + } & { + adjusters?: { + /** + * Adjuster for Complex Rules. + */ + price?: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * Adjuster for Complex Rules. + */ + weight?: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * The URL for an image displayed on the storefront when the modifier value is selected.Limit of 8MB per file. + */ + image_url?: string + purchasing_disabled?: { + /** + * Flag for whether the modifier value disables purchasing when selected on the storefront. This can be used for temporarily disabling a particular modifier value. + */ + status?: boolean + /** + * The message displayed on the storefront when the purchasing disabled status is `true`. + */ + message?: string + } + } + }) & { + /** + * The unique numeric ID of the value; increments sequentially. + */ + id?: number + } + resp_productionOption: { + data?: definitions['productOption_Full'] + /** + * Empty meta object; may be used later. + */ + meta?: { ''?: string } + } + /** + * Common Option properties. + */ + productOption_Base: { + /** + * The unique numerical ID of the option, increments sequentially. + */ + id?: number + /** + * The unique numerical ID of the product to which the option belongs. + */ + product_id?: number + /** + * The name of the option shown on the storefront. + */ + display_name?: string + /** + * The type of option, which determines how it will display on the storefront. Acceptable values: `radio_buttons`, `rectangles`, `dropdown`, `product_list`, `product_list_with_images`, `swatch`. For reference, the former v2 API values are: RB = radio_buttons, RT = rectangles, S = dropdown, P = product_list, PI = product_list_with_images, CS = swatch. + */ + type?: + | 'radio_buttons' + | 'rectangles' + | 'dropdown' + | 'product_list' + | 'product_list_with_images' + | 'swatch' + config?: definitions['productOptionConfig_Full'] + /** + * Order in which the option is displayed on the storefront. + */ + sort_order?: number + option_values?: definitions['productOptionOptionValue_Full'] + } + productOption_Full: definitions['productOption_Base'] & { + /** + * The unique option name, auto-generated from the display name, a timestamp, and the product ID. + */ + name?: string + } + /** + * The model for a POST to create options on a product. + */ + productOption_Post: { + /** + * The unique numerical ID of the option, increments sequentially. + */ + id?: number + /** + * The unique numerical ID of the product to which the option belongs. + */ + product_id?: number + /** + * The name of the option shown on the storefront. + */ + display_name?: string + /** + * The type of option, which determines how it will display on the storefront. Acceptable values: `radio_buttons`, `rectangles`, `dropdown`, `product_list`, `product_list_with_images`, `swatch`. For reference, the former v2 API values are: RB = radio_buttons, RT = rectangles, S = dropdown, P = product_list, PI = product_list_with_images, CS = swatch. + */ + type?: + | 'radio_buttons' + | 'rectangles' + | 'dropdown' + | 'product_list' + | 'product_list_with_images' + | 'swatch' + /** + * The values for option config can vary based on the Modifier created. + */ + config?: { + /** + * (date, text, multi_line_text, numbers_only_text) The default value. Shown on a date option as an ISO-8601–formatted string, or on a text option as a string. + */ + default_value?: string + /** + * (checkbox) Flag for setting the checkbox to be checked by default. + */ + checked_by_default?: boolean + /** + * (checkbox) Label displayed for the checkbox option. + */ + checkbox_label?: string + /** + * (date) Flag to limit the dates allowed to be entered on a date option. + */ + date_limited?: boolean + /** + * (date) The type of limit that is allowed to be entered on a date option. + */ + date_limit_mode?: 'earliest' | 'range' | 'latest' + /** + * (date) The earliest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_earliest_value?: string + /** + * (date) The latest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_latest_value?: string + /** + * (file) The kind of restriction on the file types that can be uploaded with a file upload option. Values: `specific` - restricts uploads to particular file types; `all` - allows all file types. + */ + file_types_mode?: 'specific' | 'all' + /** + * (file) The type of files allowed to be uploaded if the `file_type_option` is set to `specific`. Values: + * `images` - Allows upload of image MIME types (`bmp`, `gif`, `jpg`, `jpeg`, `jpe`, `jif`, `jfif`, `jfi`, `png`, `wbmp`, `xbm`, `tiff`). `documents` - Allows upload of document MIME types (`txt`, `pdf`, `rtf`, `doc`, `docx`, `xls`, `xlsx`, `accdb`, `mdb`, `one`, `pps`, `ppsx`, `ppt`, `pptx`, `pub`, `odt`, `ods`, `odp`, `odg`, `odf`). + * `other` - Allows file types defined in the `file_types_other` array. + */ + file_types_supported?: string[] + /** + * (file) A list of other file types allowed with the file upload option. + */ + file_types_other?: string[] + /** + * (file) The maximum size for a file that can be used with the file upload option. This will still be limited by the server. + */ + file_max_size?: number + /** + * (text, multi_line_text) Flag to validate the length of a text or multi-line text input. + */ + text_characters_limited?: boolean + /** + * (text, multi_line_text) The minimum length allowed for a text or multi-line text option. + */ + text_min_length?: number + /** + * (text, multi_line_text) The maximum length allowed for a text or multi line text option. + */ + text_max_length?: number + /** + * (multi_line_text) Flag to validate the maximum number of lines allowed on a multi-line text input. + */ + text_lines_limited?: boolean + /** + * (multi_line_text) The maximum number of lines allowed on a multi-line text input. + */ + text_max_lines?: number + /** + * (numbers_only_text) Flag to limit the value of a number option. + */ + number_limited?: boolean + /** + * (numbers_only_text) The type of limit on values entered for a number option. + */ + number_limit_mode?: 'lowest' | 'highest' | 'range' + /** + * (numbers_only_text) The lowest allowed value for a number option if `number_limited` is true. + */ + number_lowest_value?: number + /** + * (numbers_only_text) The highest allowed value for a number option if `number_limited` is true. + */ + number_highest_value?: number + /** + * (numbers_only_text) Flag to limit the input on a number option to whole numbers only. + */ + number_integers_only?: boolean + /** + * (product_list, product_list_with_images) Flag for automatically adjusting inventory on a product included in the list. + */ + product_list_adjusts_inventory?: boolean + /** + * (product_list, product_list_with_images) Flag to add the optional product's price to the main product's price. + */ + product_list_adjusts_pricing?: boolean + /** + * (product_list, product_list_with_images) How to factor the optional product's weight and package dimensions into the shipping quote. Values: `none` - don't adjust; `weight` - use shipping weight only; `package` - use weight and dimensions. + */ + product_list_shipping_calc?: 'none' | 'weight' | 'package' + } + /** + * Order in which the option is displayed on the storefront. + */ + sort_order?: number + option_values?: ({ + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. + */ + value_data?: { [key: string]: any } + } & { + /** + * The unique numeric ID of the value; increments sequentially. + */ + id?: number + })[] + /** + * Publicly available image url + */ + image_url?: string + } + /** + * The model for a PUT to update options on a product. + */ + productOption_Put: { + /** + * The unique numerical ID of the option, increments sequentially. + */ + id?: number + /** + * The unique numerical ID of the product to which the option belongs. + */ + product_id?: number + /** + * The name of the option shown on the storefront. + */ + display_name?: string + /** + * The type of option, which determines how it will display on the storefront. Acceptable values: `radio_buttons`, `rectangles`, `dropdown`, `product_list`, `product_list_with_images`, `swatch`. For reference, the former v2 API values are: RB = radio_buttons, RT = rectangles, S = dropdown, P = product_list, PI = product_list_with_images, CS = swatch. + */ + type?: + | 'radio_buttons' + | 'rectangles' + | 'dropdown' + | 'product_list' + | 'product_list_with_images' + | 'swatch' + /** + * The values for option config can vary based on the Modifier created. + */ + config?: { + /** + * (date, text, multi_line_text, numbers_only_text) The default value. Shown on a date option as an ISO-8601–formatted string, or on a text option as a string. + */ + default_value?: string + /** + * (checkbox) Flag for setting the checkbox to be checked by default. + */ + checked_by_default?: boolean + /** + * (checkbox) Label displayed for the checkbox option. + */ + checkbox_label?: string + /** + * (date) Flag to limit the dates allowed to be entered on a date option. + */ + date_limited?: boolean + /** + * (date) The type of limit that is allowed to be entered on a date option. + */ + date_limit_mode?: 'earliest' | 'range' | 'latest' + /** + * (date) The earliest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_earliest_value?: string + /** + * (date) The latest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_latest_value?: string + /** + * (file) The kind of restriction on the file types that can be uploaded with a file upload option. Values: `specific` - restricts uploads to particular file types; `all` - allows all file types. + */ + file_types_mode?: 'specific' | 'all' + /** + * (file) The type of files allowed to be uploaded if the `file_type_option` is set to `specific`. Values: + * `images` - Allows upload of image MIME types (`bmp`, `gif`, `jpg`, `jpeg`, `jpe`, `jif`, `jfif`, `jfi`, `png`, `wbmp`, `xbm`, `tiff`). `documents` - Allows upload of document MIME types (`txt`, `pdf`, `rtf`, `doc`, `docx`, `xls`, `xlsx`, `accdb`, `mdb`, `one`, `pps`, `ppsx`, `ppt`, `pptx`, `pub`, `odt`, `ods`, `odp`, `odg`, `odf`). + * `other` - Allows file types defined in the `file_types_other` array. + */ + file_types_supported?: string[] + /** + * (file) A list of other file types allowed with the file upload option. + */ + file_types_other?: string[] + /** + * (file) The maximum size for a file that can be used with the file upload option. This will still be limited by the server. + */ + file_max_size?: number + /** + * (text, multi_line_text) Flag to validate the length of a text or multi-line text input. + */ + text_characters_limited?: boolean + /** + * (text, multi_line_text) The minimum length allowed for a text or multi-line text option. + */ + text_min_length?: number + /** + * (text, multi_line_text) The maximum length allowed for a text or multi line text option. + */ + text_max_length?: number + /** + * (multi_line_text) Flag to validate the maximum number of lines allowed on a multi-line text input. + */ + text_lines_limited?: boolean + /** + * (multi_line_text) The maximum number of lines allowed on a multi-line text input. + */ + text_max_lines?: number + /** + * (numbers_only_text) Flag to limit the value of a number option. + */ + number_limited?: boolean + /** + * (numbers_only_text) The type of limit on values entered for a number option. + */ + number_limit_mode?: 'lowest' | 'highest' | 'range' + /** + * (numbers_only_text) The lowest allowed value for a number option if `number_limited` is true. + */ + number_lowest_value?: number + /** + * (numbers_only_text) The highest allowed value for a number option if `number_limited` is true. + */ + number_highest_value?: number + /** + * (numbers_only_text) Flag to limit the input on a number option to whole numbers only. + */ + number_integers_only?: boolean + /** + * (product_list, product_list_with_images) Flag for automatically adjusting inventory on a product included in the list. + */ + product_list_adjusts_inventory?: boolean + /** + * (product_list, product_list_with_images) Flag to add the optional product's price to the main product's price. + */ + product_list_adjusts_pricing?: boolean + /** + * (product_list, product_list_with_images) How to factor the optional product's weight and package dimensions into the shipping quote. Values: `none` - don't adjust; `weight` - use shipping weight only; `package` - use weight and dimensions. + */ + product_list_shipping_calc?: 'none' | 'weight' | 'package' + } + /** + * Order in which the option is displayed on the storefront. + */ + sort_order?: number + option_values?: ({ + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. + */ + value_data?: { [key: string]: any } + } & { + /** + * The unique numeric ID of the value; increments sequentially. + */ + id?: number + })[] + /** + * Publicly available image url + */ + image_url?: string + } + /** + * Returns the categories tree, a nested lineage of the categories with parent->child relationship. The Category objects returned are simplified versions of the category objects returned in the rest of this API. + */ + categoriesTree_Resp: { + data?: definitions['categoriesTreeNode_Full'][] + meta?: definitions['metaEmpty_Full'] + } + /** + * Used to reflect parent <> child category relationships. Used by Category Tree. + */ + categoriesTreeNode_Full: { + /** + * The unique numeric ID of the category; increments sequentially. + */ + id?: number + /** + * The unique numeric ID of the category's parent. This field controls where the category sits in the tree of categories that organize the catalog. + */ + parent_id?: number + /** + * The name displayed for the category. Name is unique with respect to the category's siblings. + */ + name?: string + /** + * Flag to determine whether the product should be displayed to customers browsing the store. If `true`, the category will be displayed. If `false`, the category will be hidden from view. + */ + is_visible?: boolean + /** + * The custom URL for the category on the storefront. + */ + url?: string + /** + * The list of children of the category. + */ + children?: definitions['categoriesTreeNode_Full'][] + } + /** + * Common Category object properties. + */ + category_Full: { + /** + * Unique ID of the *Category*. Increments sequentially. + * Read-Only. + */ + id?: number + /** + * The unique numeric ID of the category's parent. This field controls where the category sits in the tree of categories that organize the catalog. + * Required in a POST if creating a child category. + */ + parent_id: number + /** + * The name displayed for the category. Name is unique with respect to the category's siblings. + * Required in a POST. + */ + name: string + /** + * The product description, which can include HTML formatting. + */ + description?: string + /** + * Number of views the category has on the storefront. + */ + views?: number + /** + * Priority this category will be given when included in the menu and category pages. The lower the number, the closer to the top of the results the category will be. + */ + sort_order?: number + /** + * Custom title for the category page. If not defined, the category name will be used as the meta title. + */ + page_title?: string + /** + * A comma-separated list of keywords that can be used to locate the category when searching the store. + */ + search_keywords?: string + /** + * Custom meta keywords for the category page. If not defined, the store's default keywords will be used. Must post as an array like: ["awesome","sauce"]. + */ + meta_keywords?: string[] + /** + * Custom meta description for the category page. If not defined, the store's default meta description will be used. + */ + meta_description?: string + /** + * A valid layout file. (Please refer to [this article](https://support.bigcommerce.com/articles/Public/Creating-Custom-Template-Files/) on creating category files.) This field is writable only for stores with a Blueprint theme applied. + */ + layout_file?: string + /** + * Flag to determine whether the product should be displayed to customers browsing the store. If `true`, the category will be displayed. If `false`, the category will be hidden from view. + */ + is_visible?: boolean + /** + * Determines how the products are sorted on category page load. + */ + default_product_sort?: + | 'use_store_settings' + | 'featured' + | 'newest' + | 'best_selling' + | 'alpha_asc' + | 'alpha_desc' + | 'avg_customer_review' + | 'price_asc' + | 'price_desc' + /** + * Image URL used for this category on the storefront. Images can be uploaded via form file post to `/categories/{categoryId}/image`, or by providing a publicly accessible URL in this field. + */ + image_url?: string + custom_url?: definitions['customUrl_Full'] + } + /** + * Common Brand properties. + */ + brand_Full: { + /** + * Unique ID of the *Brand*. Read-Only. + */ + id?: number + /** + * The name of the brand. Must be unique. + * Required in POST. + */ + name: string + /** + * The title shown in the browser while viewing the brand. + */ + page_title?: string + /** + * Comma-separated list of meta keywords to include in the HTML. + */ + meta_keywords?: string[] + /** + * A meta description to include. + */ + meta_description?: string + /** + * A comma-separated list of keywords that can be used to locate this brand. + */ + search_keywords?: string + /** + * Image URL used for this category on the storefront. Images can be uploaded via form file post to `/brands/{brandId}/image`, or by providing a publicly accessible URL in this field. + */ + image_url?: string + custom_url?: definitions['customUrl_Full'] + } + /** + * Common Variant properties. + */ + productVariant_Base: { + /** + * The cost price of the variant. Not affected by Price List prices. + */ + cost_price?: number + /** + * This variant's base price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is `null`, the product's default price (set in the Product resource's `price` field) will be used as the base price. + */ + price?: number + /** + * This variant's sale price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's sale price (set in the Product resource's `price` field) will be used as the sale price. + */ + sale_price?: number + /** + * This variant's retail price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's retail price (set in the Product resource's `price` field) will be used as the retail price. + */ + retail_price?: number + /** + * This variant's base weight on the storefront. If this value is null, the product's default weight (set in the Product resource's weight field) will be used as the base weight. + */ + weight?: number + /** + * Width of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default width (set in the Product resource's `width` field) will be used as the base width. + */ + width?: number + /** + * Height of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default height (set in the Product resource's `height` field) will be used as the base height. + */ + height?: number + /** + * Depth of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default depth (set in the Product resource's `depth` field) will be used as the base depth. + */ + depth?: number + /** + * Flag used to indicate whether the variant has free shipping. If `true`, the shipping cost for the variant will be zero. + */ + is_free_shipping?: boolean + /** + * A fixed shipping cost for the variant. If defined, this value will be used during checkout instead of normal shipping-cost calculation. + */ + fixed_cost_shipping_price?: number + /** + * If `true`, this variant will not be purchasable on the storefront. + */ + purchasing_disabled?: boolean + /** + * If `purchasing_disabled` is `true`, this message should show on the storefront when the variant is selected. + */ + purchasing_disabled_message?: string + /** + * The UPC code used in feeds for shopping comparison sites and external channel integrations. + */ + upc?: string + /** + * Inventory level for the variant, which is used when the product's inventory_tracking is set to `variant`. + */ + inventory_level?: number + /** + * When the variant hits this inventory level, it is considered low stock. + */ + inventory_warning_level?: number + /** + * Identifies where in a warehouse the variant is located. + */ + bin_picking_number?: string + } + productVariant_Full: definitions['productVariant_Base'] & { + id?: number + product_id?: number + sku?: string + /** + * Read-only reference to v2 API's SKU ID. Null if it is a base variant. + */ + sku_id?: number + /** + * Array of option and option values IDs that make up this variant. Will be empty if the variant is the product's base variant. + */ + option_values?: definitions['productVariantOptionValue_Base'][] + /** + * The price of the variant as seen on the storefront. This price takes into account `sale_price` and any price adjustment rules that are applicable to this variant. + */ + calculated_price?: number + } + /** + * The model for a POST to create variants on a product. + */ + productVariant_Post: { + /** + * The cost price of the variant. Not affected by Price List prices. + */ + cost_price?: number + /** + * This variant's base price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is `null`, the product's default price (set in the Product resource's `price` field) will be used as the base price. + */ + price?: number + /** + * This variant's sale price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's sale price (set in the Product resource's `price` field) will be used as the sale price. + */ + sale_price?: number + /** + * This variant's retail price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's retail price (set in the Product resource's `price` field) will be used as the retail price. + */ + retail_price?: number + /** + * This variant's base weight on the storefront. If this value is null, the product's default weight (set in the Product resource's weight field) will be used as the base weight. + */ + weight?: number + /** + * Width of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default width (set in the Product resource's `width` field) will be used as the base width. + */ + width?: number + /** + * Height of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default height (set in the Product resource's `height` field) will be used as the base height. + */ + height?: number + /** + * Depth of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default depth (set in the Product resource's `depth` field) will be used as the base depth. + */ + depth?: number + /** + * Flag used to indicate whether the variant has free shipping. If `true`, the shipping cost for the variant will be zero. + */ + is_free_shipping?: boolean + /** + * A fixed shipping cost for the variant. If defined, this value will be used during checkout instead of normal shipping-cost calculation. + */ + fixed_cost_shipping_price?: number + /** + * If `true`, this variant will not be purchasable on the storefront. + */ + purchasing_disabled?: boolean + /** + * If `purchasing_disabled` is `true`, this message should show on the storefront when the variant is selected. + */ + purchasing_disabled_message?: string + /** + * The UPC code used in feeds for shopping comparison sites and external channel integrations. + */ + upc?: string + /** + * Inventory level for the variant, which is used when the product's inventory_tracking is set to `variant`. + */ + inventory_level?: number + /** + * When the variant hits this inventory level, it is considered low stock. + */ + inventory_warning_level?: number + /** + * Identifies where in a warehouse the variant is located. + */ + bin_picking_number?: string + } & { + product_id?: number + sku?: string + /** + * Array of option and option values IDs that make up this variant. Will be empty if the variant is the product's base variant. + */ + option_values?: { id?: number; option_id?: number }[] + } + variantCollection_Put: definitions['productVariant_Full'][] + /** + * The model for a PUT to update variants on a product. + */ + variant_Put: { + /** + * The cost price of the variant. Not affected by Price List prices. + */ + cost_price?: number + /** + * This variant's base price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is `null`, the product's default price (set in the Product resource's `price` field) will be used as the base price. + */ + price?: number + /** + * This variant's sale price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's sale price (set in the Product resource's `price` field) will be used as the sale price. + */ + sale_price?: number + /** + * This variant's retail price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's retail price (set in the Product resource's `price` field) will be used as the retail price. + */ + retail_price?: number + /** + * This variant's base weight on the storefront. If this value is null, the product's default weight (set in the Product resource's weight field) will be used as the base weight. + */ + weight?: number + /** + * Width of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default width (set in the Product resource's `width` field) will be used as the base width. + */ + width?: number + /** + * Height of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default height (set in the Product resource's `height` field) will be used as the base height. + */ + height?: number + /** + * Depth of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default depth (set in the Product resource's `depth` field) will be used as the base depth. + */ + depth?: number + /** + * Flag used to indicate whether the variant has free shipping. If `true`, the shipping cost for the variant will be zero. + */ + is_free_shipping?: boolean + /** + * A fixed shipping cost for the variant. If defined, this value will be used during checkout instead of normal shipping-cost calculation. + */ + fixed_cost_shipping_price?: number + /** + * If `true`, this variant will not be purchasable on the storefront. + */ + purchasing_disabled?: boolean + /** + * If `purchasing_disabled` is `true`, this message should show on the storefront when the variant is selected. + */ + purchasing_disabled_message?: string + /** + * The UPC code used in feeds for shopping comparison sites and external channel integrations. + */ + upc?: string + /** + * Inventory level for the variant, which is used when the product's inventory_tracking is set to `variant`. + */ + inventory_level?: number + /** + * When the variant hits this inventory level, it is considered low stock. + */ + inventory_warning_level?: number + /** + * Identifies where in a warehouse the variant is located. + */ + bin_picking_number?: string + } & { id?: number } + /** + * The model for a POST to create variants on a product. + */ + productVariant_Post_Product: definitions['productVariant_Base'] & { + sku?: string + option_values?: { + /** + * The name of the option. + */ + option_display_name?: string + /** + * The label of the option value. + */ + label?: string + }[] + } + /** + * The model for a PUT to update variants on a product. + */ + productVariant_Put_Product: { + /** + * The cost price of the variant. Not affected by Price List prices. + */ + cost_price?: number + /** + * This variant's base price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is `null`, the product's default price (set in the Product resource's `price` field) will be used as the base price. + */ + price?: number + /** + * This variant's sale price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's sale price (set in the Product resource's `price` field) will be used as the sale price. + */ + sale_price?: number + /** + * This variant's retail price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's retail price (set in the Product resource's `price` field) will be used as the retail price. + */ + retail_price?: number + /** + * This variant's base weight on the storefront. If this value is null, the product's default weight (set in the Product resource's weight field) will be used as the base weight. + */ + weight?: number + /** + * Width of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default width (set in the Product resource's `width` field) will be used as the base width. + */ + width?: number + /** + * Height of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default height (set in the Product resource's `height` field) will be used as the base height. + */ + height?: number + /** + * Depth of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default depth (set in the Product resource's `depth` field) will be used as the base depth. + */ + depth?: number + /** + * Flag used to indicate whether the variant has free shipping. If `true`, the shipping cost for the variant will be zero. + */ + is_free_shipping?: boolean + /** + * A fixed shipping cost for the variant. If defined, this value will be used during checkout instead of normal shipping-cost calculation. + */ + fixed_cost_shipping_price?: number + /** + * If `true`, this variant will not be purchasable on the storefront. + */ + purchasing_disabled?: boolean + /** + * If `purchasing_disabled` is `true`, this message should show on the storefront when the variant is selected. + */ + purchasing_disabled_message?: string + /** + * The UPC code used in feeds for shopping comparison sites and external channel integrations. + */ + upc?: string + /** + * Inventory level for the variant, which is used when the product's inventory_tracking is set to `variant`. + */ + inventory_level?: number + /** + * When the variant hits this inventory level, it is considered low stock. + */ + inventory_warning_level?: number + /** + * Identifies where in a warehouse the variant is located. + */ + bin_picking_number?: string + product_id?: number + sku?: string + } + productVariantOptionValue_Full: { + /** + * The name of the option. + */ + option_display_name?: string + /** + * The label of the option value. + */ + label?: string + } & definitions['productVariantOptionValue_Base'] + /** + * The model for a POST to create option values on a product. + */ + productOptionValue_Post_Product: { + /** + * The name of the option. + */ + option_display_name?: string + /** + * The label of the option value. + */ + label?: string + } + /** + * Common Product Variant Option properties. + */ + productVariantOptionValue_Base: { id?: number; option_id?: number } + /** + * The model for a POST to create option values on a variant. + */ + productVariantOptionValue_Post: { id?: number; option_id?: number } + resp_productOptionValue: { + data?: definitions['productOptionOptionValue_Full'] + /** + * Empty meta object; may be used later. + */ + meta?: { ''?: string } + } + /** + * Common Product Option `option_value` properties. + */ + productOptionOptionValue_Base: { + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. If no data is available, returns `null`. + */ + value_data?: { [key: string]: any } + } + /** + * Product Option `option_value`. + */ + productOptionOptionValue_Full: definitions['productOptionOptionValue_Base'] & { + /** + * The unique numeric ID of the value; increments sequentially. + */ + id?: number + } + /** + * The model for a POST to create option values on a product. + */ + productOptionValue_Post: { + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. + */ + value_data?: { [key: string]: any } + } + /** + * The model for a PUT to update option values on a product. + */ + productOptionValue_Put: { + /** + * The flag for preselecting a value as the default on the storefront. This field is not supported for swatch options/modifiers. + */ + is_default?: boolean + /** + * The text display identifying the value on the storefront. Required in a /POST. + */ + label: string + /** + * The order in which the value will be displayed on the product page. Required in a /POST. + */ + sort_order: number + /** + * Extra data describing the value, based on the type of option or modifier with which the value is associated. The `swatch` type option can accept an array of `colors`, with up to three hexidecimal color keys; or an `image_url`, which is a full image URL path including protocol. The `product list` type option requires a `product_id`. The `checkbox` type option requires a boolean flag, called `checked_value`, to determine which value is considered to be the checked state. + */ + value_data?: { [key: string]: any } + } & { + /** + * The unique numeric ID of the value; increments sequentially. + */ + id?: number + } + /** + * Common ProductImage properties. + */ + productImage_Base: { + /** + * The local path to the original image file uploaded to BigCommerce. + */ + image_file?: string + /** + * Flag for identifying whether the image is used as the product's thumbnail. + */ + is_thumbnail?: boolean + /** + * The order in which the image will be displayed on the product page. Higher integers give the image a lower priority. When updating, if the image is given a lower priority, all images with a `sort_order` the same as or greater than the image's new `sort_order` value will have their `sort_order`s reordered. + */ + sort_order?: number + /** + * The description for the image. + */ + description?: string + /** + * Must be a fully qualified URL path, including protocol. Limit of 8MB per file. + */ + image_url?: string + } + /** + * The model for a POST to create an image on a product. + */ + productImage_Post: { + /** + * The unique numeric ID of the image; increments sequentially. + */ + id?: number + /** + * The unique numeric identifier for the product with which the image is associated. + */ + product_id?: number + /** + * The local path to the original image file uploaded to BigCommerce. + */ + image_file?: string + /** + * The zoom URL for this image. By default, this is used as the zoom image on product pages when zoom images are enabled. + */ + url_zoom?: string + /** + * The standard URL for this image. By default, this is used for product-page images. + */ + url_standard?: string + /** + * The thumbnail URL for this image. By default, this is the image size used on the category page and in side panels. + */ + url_thumbnail?: string + /** + * The tiny URL for this image. By default, this is the image size used for thumbnails beneath the product image on a product page. + */ + url_tiny?: string + /** + * The date on which the product image was modified. + */ + date_modified?: string + /** + * Flag for identifying whether the image is used as the product's thumbnail. + */ + is_thumbnail?: boolean + /** + * The order in which the image will be displayed on the product page. Higher integers give the image a lower priority. When updating, if the image is given a lower priority, all images with a `sort_order` the same as or greater than the image's new `sort_order` value will have their `sort_order`s reordered. + */ + sort_order?: number + /** + * The description for the image. + */ + description?: string + } & { + /** + * Must be a fully qualified URL path, including protocol. Limit of 8MB per file. + */ + image_url?: string + /** + * Must be sent as a multipart/form-data field in the request body. + */ + image_file?: string + } + /** + * The model for a PUT to update applicable Product Image fields. + */ + productImage_Put: { + /** + * The unique numeric ID of the image; increments sequentially. + */ + id?: number + /** + * The unique numeric identifier for the product with which the image is associated. + */ + product_id?: number + /** + * The local path to the original image file uploaded to BigCommerce. + */ + image_file?: string + /** + * The zoom URL for this image. By default, this is used as the zoom image on product pages when zoom images are enabled. + */ + url_zoom?: string + /** + * The standard URL for this image. By default, this is used for product-page images. + */ + url_standard?: string + /** + * The thumbnail URL for this image. By default, this is the image size used on the category page and in side panels. + */ + url_thumbnail?: string + /** + * The tiny URL for this image. By default, this is the image size used for thumbnails beneath the product image on a product page. + */ + url_tiny?: string + /** + * The date on which the product image was modified. + */ + date_modified?: string + /** + * Flag for identifying whether the image is used as the product's thumbnail. + */ + is_thumbnail?: boolean + /** + * The order in which the image will be displayed on the product page. Higher integers give the image a lower priority. When updating, if the image is given a lower priority, all images with a `sort_order` the same as or greater than the image's new `sort_order` value will have their `sort_order`s reordered. + */ + sort_order?: number + /** + * The description for the image. + */ + description?: string + } + /** + * The model for a POST to create a video on a product. + */ + productVideo_Base: { + /** + * The title for the video. If left blank, this will be filled in according to data on a host site. + */ + title?: string + /** + * The description for the video. If left blank, this will be filled in according to data on a host site. + */ + description?: string + /** + * The order in which the video will be displayed on the product page. Higher integers give the video a lower priority. When updating, if the video is given a lower priority, all videos with a `sort_order` the same as or greater than the video's new `sort_order` value will have their `sort_order`s reordered. + */ + sort_order?: number + /** + * The video type (a short name of a host site). + */ + type?: 'youtube' + /** + * The ID of the video on a host site. + */ + video_id?: string + } + /** + * A product video model. + */ + productVideo_Full: definitions['productVideo_Base'] & { + /** + * The unique numeric ID of the product video; increments sequentially. + */ + id?: number + /** + * The unique numeric identifier for the product with which the image is associated. + */ + product_id?: number + /** + * Length of the video. This will be filled in according to data on a host site. + */ + length?: string + } + /** + * The model for a POST to create a video on a product. + */ + productVideo_Post: definitions['productVideo_Base'] + /** + * The model for a PUT to update a video on a product. + */ + productVideo_Put: definitions['productVideo_Base'] & { + /** + * The unique numeric ID of the product video; increments sequentially. + */ + id?: number + } + productReview_Base: { + /** + * The title for the product review. + * Required in /POST. + */ + title: string + /** + * The text for the product review. + */ + text?: string + /** + * The status of the product review. Must be one of `approved`, `disapproved` or `pending`. + */ + status?: string + /** + * The rating of the product review. Must be one of 0, 1, 2, 3, 4, 5. + */ + rating?: number + /** + * The email of the reviewer. Must be a valid email, or an empty string. + */ + email?: string + /** + * The name of the reviewer. + */ + name?: string + /** + * Date the product was reviewed. Required in /POST. + */ + date_reviewed: string + } + /** + * A product review model. + */ + productReview_Full: definitions['productReview_Base'] & { + /** + * The unique numeric ID of the product review; increments sequentially. + */ + id?: number + /** + * The unique numeric identifier for the product with which the review is associated. + */ + product_id?: number + /** + * Date the product review was created. + */ + date_created?: string + /** + * Date the product review was modified. + */ + date_modified?: string + } + /** + * The model for a POST to create a product review. + */ + productReview_Post: { + /** + * The title for the product review. + * Required in /POST. + */ + title: string + /** + * The text for the product review. + */ + text?: string + /** + * The status of the product review. Must be one of `approved`, `disapproved` or `pending`. + */ + status?: string + /** + * The rating of the product review. Must be one of 0, 1, 2, 3, 4, 5. + */ + rating?: number + /** + * The email of the reviewer. Must be a valid email, or an empty string. + */ + email?: string + /** + * The name of the reviewer. + */ + name?: string + /** + * Date the product was reviewed. Required in /POST. + */ + date_reviewed: string + } + /** + * The model for a PUT to update a product review. + */ + productReview_Put: { + /** + * The title for the product review. + * Required in /POST. + */ + title: string + /** + * The text for the product review. + */ + text?: string + /** + * The status of the product review. Must be one of `approved`, `disapproved` or `pending`. + */ + status?: string + /** + * The rating of the product review. Must be one of 0, 1, 2, 3, 4, 5. + */ + rating?: number + /** + * The email of the reviewer. Must be a valid email, or an empty string. + */ + email?: string + /** + * The name of the reviewer. + */ + name?: string + /** + * Date the product was reviewed. Required in /POST. + */ + date_reviewed: string + } + /** + * Image Response returns for: + * * Create Variant Image + * * Create Modifier Image + * * Create Category Image + * * Create Brand Image + */ + resp_productImage: { + data?: definitions['productImage_Full'] + /** + * Empty meta object; may be used later. + */ + meta?: { [key: string]: any } + } + /** + * An object containing a publicly accessible image URL, or a form post that contains an image file. + */ + resourceImage_Full: { + /** + * A public URL for a GIF, JPEG, or PNG image. Limit of 8MB per file. + */ + image_url?: string + } + product_Post: definitions['product_Base'] & { + variants?: definitions['productVariant_Post_Product'] + } + /** + * The model for a PUT to update a product. + */ + product_Put: { + /** + * The unique numerical ID of the product; increments sequentially. + */ + id?: number + } & definitions['product_Base'] & { + variants?: definitions['productVariant_Put_Product'] + } + /** + * Catalog Summary object describes a lightweight summary of the catalog. + */ + catalogSummary_Full: { + /** + * A count of all inventory items in the catalog. + */ + inventory_count?: number + /** + * Total value of store's inventory. + */ + inventory_value?: number + /** + * ID of the category containing the most products. + */ + primary_category_id?: number + /** + * Name of the category containing the most products. + */ + primary_category_name?: string + /** + * Total number of variants + */ + variant_count?: number + /** + * Highest priced variant + */ + highest_variant_price?: number + /** + * Average price of all variants + */ + average_variant_price?: number + /** + * Lowest priced variant in the store + */ + lowest_variant_price?: string + oldest_variant_date?: string + newest_variant_date?: string + } + /** + * Metafield for products, categories, variants, and brands. The max number of metafields allowed on each product, category, variant, or brand is fifty. For more information, see [Platform Limits](https://support.bigcommerce.com/s/article/Platform-Limits) in the Help Center. + */ + metafield_Base: { + /** + * Unique ID of the *Metafield*. Read-Only. + */ + id?: number + /** + * Determines the visibility and writeability of the field by other API consumers. + * + * |Value|Description + * |-|-| + * |`app_only`|Private to the app that owns the field| + * |`read`|Visible to other API consumers| + * |`write`|Open for reading and writing by other API consumers| + * |`read_and_sf_access`|Visible to other API consumers, including on storefront| + * |`write_and_sf_access`|Open for reading and writing by other API consumers, including on storefront| + */ + permission_set: + | 'app_only' + | 'read' + | 'write' + | 'read_and_sf_access' + | 'write_and_sf_access' + /** + * Namespace for the metafield, for organizational purposes. This is set set by the developer. Required for POST. + */ + namespace: string + /** + * The name of the field, for example: `location_id`, `color`. Required for POST. + */ + key: string + /** + * The value of the field, for example: `1`, `blue`. Required for POST. + */ + value: string + /** + * Description for the metafields. + */ + description?: string + /** + * The type of resource with which the metafield is associated. + */ + resource_type?: 'category' | 'brand' | 'product' | 'variant' + /** + * The ID for the resource with which the metafield is associated. + */ + resource_id?: number + /** + * Date and time of the metafield's creation. Read-Only. + */ + date_created?: string + /** + * Date and time when the metafield was last updated. Read-Only. + */ + date_modified?: string + } + /** + * Common ComplexRule properties. + */ + complexRule_Base: { + /** + * The unique numeric ID of the rule; increments sequentially. + * Read-Only + */ + id?: number + /** + * The unique numeric ID of the product with which the rule is associated; increments sequentially. + */ + product_id?: number + /** + * The priority to give this rule when making adjustments to the product properties. + */ + sort_order?: number + /** + * Flag for determining whether the rule is to be used when adjusting a product's price, weight, image, or availabilty. + */ + enabled?: boolean + /** + * Flag for determining whether other rules should not be applied after this rule has been applied. + */ + stop?: boolean + /** + * Flag for determining whether the rule should disable purchasing of a product when the conditions are applied. + */ + purchasing_disabled?: boolean + /** + * Message displayed on the storefront when a rule disables the purchasing of a product. + */ + purchasing_disabled_message?: string + /** + * Flag for determining whether the rule should hide purchasing of a product when the conditions are applied. + */ + purchasing_hidden?: boolean + /** + * The URL for an image displayed on the storefront when the conditions are applied. Limit of 8MB per file. + */ + image_url?: string + price_adjuster?: definitions['adjuster_Full'] + weight_adjuster?: definitions['adjuster_Full'] + conditions?: definitions['complexRuleConditionBase'][] + } + /** + * Gets custom fields associated with a product. These allow you to specify additional information that will appear on the product's page, such as a book's ISBN or a DVD's release date. + */ + productCustomField_Base: { + /** + * The unique numeric ID of the custom field; increments sequentially. + * Read-Only + */ + id?: number + /** + * The name of the field, shown on the storefront, orders, etc. Required for /POST + */ + name: string + /** + * The name of the field, shown on the storefront, orders, etc. Required for /POST + */ + value: string + } + /** + * The model for a POST to create a custom field on a product. + */ + productCustomField_Post: { + /** + * The unique numeric ID of the custom field; increments sequentially. + * Read-Only + */ + id?: number + /** + * The name of the field, shown on the storefront, orders, etc. Required for /POST + */ + name: string + /** + * The name of the field, shown on the storefront, orders, etc. Required for /POST + */ + value: string + } + /** + * The model for a PUT to update a custom field on a product. + */ + productCustomField_Put: { + /** + * The unique numeric ID of the custom field; increments sequentially. + * Read-Only + */ + id?: number + /** + * The name of the field, shown on the storefront, orders, etc. Required for /POST + */ + name: string + /** + * The name of the field, shown on the storefront, orders, etc. Required for /POST + */ + value: string + } + /** + * Complex rules may return with conditions that apply to one or more variants, or with a single modifier value (if the rules were created using the v2 API or the control panel). Complex rules created or updated in the v3 API must have conditions that either reference multiple `modifier_value_id`'s, or else reference a `modifier_value_id` and a `variant_id`. + */ + complexRuleConditionBase: { + /** + * The unique numeric ID of the rule condition; increments sequentially. Read-Only + */ + id?: number + /** + * The unique numeric ID of the rule with which the condition is associated. + * Read-Only + */ + rule_id?: number + /** + * The unique numeric ID of the modifier with which the rule condition is associated. + * Required in /POST. + */ + modifier_id: number + /** + * The unique numeric ID of the modifier value with which the rule condition is associated. + * Required in /POST. + */ + modifier_value_id: number + /** + * The unique numeric ID of the variant with which the rule condition is associated. + * Required in /POST. + */ + variant_id: number + /** + * (READ-ONLY:) The unique numeric ID of the SKU (v2 API), or Combination, with which the rule condition is associated. This is to maintain cross-compatibility between v2 and v3. + */ + combination_id?: number + } + /** + * The custom URL for the category on the storefront. + */ + customUrl_Full: { + /** + * Category URL on the storefront. + */ + url?: string + /** + * Returns `true` if the URL has been changed from its default state (the auto-assigned URL that BigCommerce provides). + */ + is_customized?: boolean + } + /** + * Common Bulk Pricing Rule properties + */ + bulkPricingRule_Full: { + /** + * Unique ID of the *Bulk Pricing Rule*. Read-Only. + */ + id?: number + /** + * The minimum inclusive quantity of a product to satisfy this rule. Must be greater than or equal to zero. + * Required in /POST. + */ + quantity_min: number + /** + * The maximum inclusive quantity of a product to satisfy this rule. Must be greater than the `quantity_min` value – unless this field has a value of 0 (zero), in which case there will be no maximum bound for this rule. + * Required in /POST. + */ + quantity_max: number + /** + * The type of adjustment that is made. Values: `price` - the adjustment amount per product; `percent` - the adjustment as a percentage of the original price; `fixed` - the adjusted absolute price of the product. + * Required in /POST. + */ + type: 'price' | 'percent' | 'fixed' + /** + * The discount can be a fixed dollar amount or a percentage. For a fixed dollar amount enter it as an integer and the response will return as an integer. For percentage enter the amount as the percentage divided by 100 using string format. For example 10% percent would be “.10”. The response will return as an integer. + * Required in /POST. + */ + amount: number + } + /** + * The values for option config can vary based on the Modifier created. + */ + productOptionConfig_Full: { + /** + * (date, text, multi_line_text, numbers_only_text) The default value. Shown on a date option as an ISO-8601–formatted string, or on a text option as a string. + */ + default_value?: string + /** + * (checkbox) Flag for setting the checkbox to be checked by default. + */ + checked_by_default?: boolean + /** + * (checkbox) Label displayed for the checkbox option. + */ + checkbox_label?: string + /** + * (date) Flag to limit the dates allowed to be entered on a date option. + */ + date_limited?: boolean + /** + * (date) The type of limit that is allowed to be entered on a date option. + */ + date_limit_mode?: 'earliest' | 'range' | 'latest' + /** + * (date) The earliest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_earliest_value?: string + /** + * (date) The latest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_latest_value?: string + /** + * (file) The kind of restriction on the file types that can be uploaded with a file upload option. Values: `specific` - restricts uploads to particular file types; `all` - allows all file types. + */ + file_types_mode?: 'specific' | 'all' + /** + * (file) The type of files allowed to be uploaded if the `file_type_option` is set to `specific`. Values: + * `images` - Allows upload of image MIME types (`bmp`, `gif`, `jpg`, `jpeg`, `jpe`, `jif`, `jfif`, `jfi`, `png`, `wbmp`, `xbm`, `tiff`). `documents` - Allows upload of document MIME types (`txt`, `pdf`, `rtf`, `doc`, `docx`, `xls`, `xlsx`, `accdb`, `mdb`, `one`, `pps`, `ppsx`, `ppt`, `pptx`, `pub`, `odt`, `ods`, `odp`, `odg`, `odf`). + * `other` - Allows file types defined in the `file_types_other` array. + */ + file_types_supported?: string[] + /** + * (file) A list of other file types allowed with the file upload option. + */ + file_types_other?: string[] + /** + * (file) The maximum size for a file that can be used with the file upload option. This will still be limited by the server. + */ + file_max_size?: number + /** + * (text, multi_line_text) Flag to validate the length of a text or multi-line text input. + */ + text_characters_limited?: boolean + /** + * (text, multi_line_text) The minimum length allowed for a text or multi-line text option. + */ + text_min_length?: number + /** + * (text, multi_line_text) The maximum length allowed for a text or multi line text option. + */ + text_max_length?: number + /** + * (multi_line_text) Flag to validate the maximum number of lines allowed on a multi-line text input. + */ + text_lines_limited?: boolean + /** + * (multi_line_text) The maximum number of lines allowed on a multi-line text input. + */ + text_max_lines?: number + /** + * (numbers_only_text) Flag to limit the value of a number option. + */ + number_limited?: boolean + /** + * (numbers_only_text) The type of limit on values entered for a number option. + */ + number_limit_mode?: 'lowest' | 'highest' | 'range' + /** + * (numbers_only_text) The lowest allowed value for a number option if `number_limited` is true. + */ + number_lowest_value?: number + /** + * (numbers_only_text) The highest allowed value for a number option if `number_limited` is true. + */ + number_highest_value?: number + /** + * (numbers_only_text) Flag to limit the input on a number option to whole numbers only. + */ + number_integers_only?: boolean + /** + * (product_list, product_list_with_images) Flag for automatically adjusting inventory on a product included in the list. + */ + product_list_adjusts_inventory?: boolean + /** + * (product_list, product_list_with_images) Flag to add the optional product's price to the main product's price. + */ + product_list_adjusts_pricing?: boolean + /** + * (product_list, product_list_with_images) How to factor the optional product's weight and package dimensions into the shipping quote. Values: `none` - don't adjust; `weight` - use shipping weight only; `package` - use weight and dimensions. + */ + product_list_shipping_calc?: 'none' | 'weight' | 'package' + } + /** + * Adjuster for Complex Rules. + */ + adjuster_Full: { + /** + * The type of adjuster for either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster?: 'relative' | 'percentage' + /** + * The numeric amount by which the adjuster will change either the price or the weight of the variant, when the modifier value is selected on the storefront. + */ + adjuster_value?: number + } + /** + * Errors during batch usage for the BigCommerce API. + */ + resp_variantBatchError: { + batch_errors?: (definitions['error_Base'] & { + errors?: { additionalProperties?: string } + })[] + } + /** + * Data about the response, including pagination and collection totals. + */ + metaCollection_Full: { pagination?: definitions['pagination_Full'] } + /** + * Data about the response, including pagination and collection totals. + */ + pagination_Full: { + /** + * Total number of items in the result set. + */ + total?: number + /** + * Total number of items in the collection response. + */ + count?: number + /** + * The amount of items returned in the collection per page, controlled by the limit parameter. + */ + per_page?: number + /** + * The page you are currently on within the collection. + */ + current_page?: number + /** + * The total number of pages in the collection. + */ + total_pages?: number + /** + * Pagination links for the previous and next parts of the whole collection. + */ + links?: { + /** + * Link to the previous page returned in the response. + */ + previous?: string + /** + * Link to the current page returned in the response. + */ + current?: string + /** + * Link to the next page returned in the response. + */ + next?: string + } + } + /** + * Empty meta object; may be used later. + */ + metaEmpty_Full: { [key: string]: any } + errorResponse_Full: definitions['error_Base'] & { + errors?: definitions['detailedErrors'] + } + /** + * Error payload for the BigCommerce API. + */ + error_Base: { + /** + * The HTTP status code. + */ + status?: number + /** + * The error title describing the particular error. + */ + title?: string + type?: string + instance?: string + } + /** + * Error payload for the BigCommerce API. + */ + errorNotFound: { + /** + * 404 HTTP status code. + */ + status?: number + /** + * The error title describing the particular error. + */ + title?: string + type?: string + instance?: string + } + /** + * A gift-certificate model. + */ + giftCertificate_Full: { + /** + * The gift-certificate code. + */ + code?: string + /** + * The balance on a gift certificate when it was purchased. + */ + original_balance?: number + /** + * The balance on a gift certificate at the time of this purchase. + */ + starting_balance?: number + /** + * The remaining balance on a gift certificate. + */ + remaining_balance?: number + /** + * The status of a gift certificate: `active` - gift certificate is active; `pending` - gift certificate purchase is pending; `disabled` - gift certificate is disabled; `expired` - gift certificate is expired. + */ + status?: 'active' | 'pending' | 'disabled' | 'expired' + } + /** + * No-content response for the BigCommerce API. + */ + errorNoContent: { + /** + * 204 HTTP status code. + */ + status?: number + /** + * The error title describing the situation. + */ + title?: string + type?: string + instance?: string + } + detailedErrors: { additionalProperties?: string } + product_Full: definitions['product_Base'] & { + /** + * The date on which the product was created. + */ + date_created?: string + /** + * The date on which the product was modified. + */ + date_modified?: string + /** + * ID of the product. Read Only. + */ + id?: number + /** + * The unique identifier of the base variant associated with a simple product. This value is `null` for complex products. + */ + base_variant_id?: number + /** + * The price of the product as seen on the storefront. It will be equal to the `sale_price`, if set, and the `price` if there is not a `sale_price`. + */ + calculated_price?: number + options?: definitions['productOption_Base'][] + modifiers?: definitions['productModifier_Full'][] + /** + * Minimum Advertised Price. + */ + map_price?: number + /** + * Indicates that the product is in an Option Set (legacy V2 concept). + */ + option_set_id?: number + /** + * Legacy template setting which controls if the option set shows up to the side of or below the product image and description. + */ + option_set_display?: string + } & { variants?: definitions['productVariant_Full'] } + /** + * Common ProductImage properties. + */ + productImage_Full: definitions['productImage_Base'] & { + /** + * The unique numeric ID of the image; increments sequentially. + */ + id?: number + /** + * The unique numeric identifier for the product with which the image is associated. + */ + product_id?: number + /** + * The zoom URL for this image. By default, this is used as the zoom image on product pages when zoom images are enabled. + */ + url_zoom?: string + /** + * The standard URL for this image. By default, this is used for product-page images. + */ + url_standard?: string + /** + * The thumbnail URL for this image. By default, this is the image size used on the category page and in side panels. + */ + url_thumbnail?: string + /** + * The tiny URL for this image. By default, this is the image size used for thumbnails beneath the product image on a product page. + */ + url_tiny?: string + /** + * The date on which the product image was modified. + */ + date_modified?: string + } + metafield_Post: definitions['metafield_Base'] + /** + * The model for batch updating products. + */ + product_Put_Collection: ({ + /** + * The unique numerical ID of the product; increments sequentially. Required on batch product `PUT` requests. + */ + id: number + } & definitions['product_Base'])[] + /** + * The values for option config can vary based on the Modifier created. + */ + config_Full: { + /** + * (date, text, multi_line_text, numbers_only_text) The default value. Shown on a date option as an ISO-8601–formatted string, or on a text option as a string. + */ + default_value?: string + /** + * (checkbox) Flag for setting the checkbox to be checked by default. + */ + checked_by_default?: boolean + /** + * (checkbox) Label displayed for the checkbox option. + */ + checkbox_label?: string + /** + * (date) Flag to limit the dates allowed to be entered on a date option. + */ + date_limited?: boolean + /** + * (date) The type of limit that is allowed to be entered on a date option. + */ + date_limit_mode?: 'earliest' | 'range' | 'latest' + /** + * (date) The earliest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_earliest_value?: string + /** + * (date) The latest date allowed to be entered on the date option, as an ISO-8601 formatted string. + */ + date_latest_value?: string + /** + * (file) The kind of restriction on the file types that can be uploaded with a file upload option. Values: `specific` - restricts uploads to particular file types; `all` - allows all file types. + */ + file_types_mode?: 'specific' | 'all' + /** + * (file) The type of files allowed to be uploaded if the `file_type_option` is set to `specific`. Values: + * `images` - Allows upload of image MIME types (`bmp`, `gif`, `jpg`, `jpeg`, `jpe`, `jif`, `jfif`, `jfi`, `png`, `wbmp`, `xbm`, `tiff`). `documents` - Allows upload of document MIME types (`txt`, `pdf`, `rtf`, `doc`, `docx`, `xls`, `xlsx`, `accdb`, `mdb`, `one`, `pps`, `ppsx`, `ppt`, `pptx`, `pub`, `odt`, `ods`, `odp`, `odg`, `odf`). + * `other` - Allows file types defined in the `file_types_other` array. + */ + file_types_supported?: string[] + /** + * (file) A list of other file types allowed with the file upload option. + */ + file_types_other?: string[] + /** + * (file) The maximum size for a file that can be used with the file upload option. This will still be limited by the server. + */ + file_max_size?: number + /** + * (text, multi_line_text) Flag to validate the length of a text or multi-line text input. + */ + text_characters_limited?: boolean + /** + * (text, multi_line_text) The minimum length allowed for a text or multi-line text option. + */ + text_min_length?: number + /** + * (text, multi_line_text) The maximum length allowed for a text or multi line text option. + */ + text_max_length?: number + /** + * (multi_line_text) Flag to validate the maximum number of lines allowed on a multi-line text input. + */ + text_lines_limited?: boolean + /** + * (multi_line_text) The maximum number of lines allowed on a multi-line text input. + */ + text_max_lines?: number + /** + * (numbers_only_text) Flag to limit the value of a number option. + */ + number_limited?: boolean + /** + * (numbers_only_text) The type of limit on values entered for a number option. + */ + number_limit_mode?: 'lowest' | 'highest' | 'range' + /** + * (numbers_only_text) The lowest allowed value for a number option if `number_limited` is true. + */ + number_lowest_value?: number + /** + * (numbers_only_text) The highest allowed value for a number option if `number_limited` is true. + */ + number_highest_value?: number + /** + * (numbers_only_text) Flag to limit the input on a number option to whole numbers only. + */ + number_integers_only?: boolean + /** + * (product_list, product_list_with_images) Flag for automatically adjusting inventory on a product included in the list. + */ + product_list_adjusts_inventory?: boolean + /** + * (product_list, product_list_with_images) Flag to add the optional product's price to the main product's price. + */ + product_list_adjusts_pricing?: boolean + /** + * (product_list, product_list_with_images) How to factor the optional product's weight and package dimensions into the shipping quote. Values: `none` - don't adjust; `weight` - use shipping weight only; `package` - use weight and dimensions. + */ + product_list_shipping_calc?: 'none' | 'weight' | 'package' + } + adjusters_Full: { + price?: definitions['adjuster_Full'] + weight?: definitions['adjuster_Full'] + /** + * The URL for an image displayed on the storefront when the modifier value is selected.Limit of 8MB per file. + */ + image_url?: string + purchasing_disabled?: { + /** + * Flag for whether the modifier value disables purchasing when selected on the storefront. This can be used for temporarily disabling a particular modifier value. + */ + status?: boolean + /** + * The message displayed on the storefront when the purchasing disabled status is `true`. + */ + message?: string + } + } + /** + * Variant properties used on: + * * `/catalog/products/variants` + * * `/catalog/variants` + */ + variant_Base: { + /** + * The cost price of the variant. Not affected by Price List prices. + */ + cost_price?: number + /** + * This variant's base price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is `null`, the product's default price (set in the Product resource's `price` field) will be used as the base price. + */ + price?: number + /** + * This variant's sale price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's sale price (set in the Product resource's `price` field) will be used as the sale price. + */ + sale_price?: number + /** + * This variant's retail price on the storefront. If a Price List ID is used, the Price List value will be used. If a Price List ID is not used, and this value is null, the product's retail price (set in the Product resource's `price` field) will be used as the retail price. + */ + retail_price?: number + /** + * This variant's base weight on the storefront. If this value is null, the product's default weight (set in the Product resource's weight field) will be used as the base weight. + */ + weight?: number + /** + * Width of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default width (set in the Product resource's `width` field) will be used as the base width. + */ + width?: number + /** + * Height of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default height (set in the Product resource's `height` field) will be used as the base height. + */ + height?: number + /** + * Depth of the variant, which can be used when calculating shipping costs. If this value is `null`, the product's default depth (set in the Product resource's `depth` field) will be used as the base depth. + */ + depth?: number + /** + * Flag used to indicate whether the variant has free shipping. If `true`, the shipping cost for the variant will be zero. + */ + is_free_shipping?: boolean + /** + * A fixed shipping cost for the variant. If defined, this value will be used during checkout instead of normal shipping-cost calculation. + */ + fixed_cost_shipping_price?: number + /** + * If `true`, this variant will not be purchasable on the storefront. + */ + purchasing_disabled?: boolean + /** + * If `purchasing_disabled` is `true`, this message should show on the storefront when the variant is selected. + */ + purchasing_disabled_message?: string + /** + * The UPC code used in feeds for shopping comparison sites and external channel integrations. + */ + upc?: string + /** + * Inventory level for the variant, which is used when the product's inventory_tracking is set to `variant`. + */ + inventory_level?: number + /** + * When the variant hits this inventory level, it is considered low stock. + */ + inventory_warning_level?: number + /** + * Identifies where in a warehouse the variant is located. + */ + bin_picking_number?: string + } + /** + * Shared `Product` properties used in: + * * `POST` + * * `PUT` + * * `GET` + */ + product_Base: { + /** + * The product name. + */ + name?: string + /** + * The product type. One of: `physical` - a physical stock unit, `digital` - a digital download. + */ + type?: 'physical' | 'digital' + /** + * User defined product code/stock keeping unit (SKU). + */ + sku?: string + /** + * The product description, which can include HTML formatting. + */ + description?: string + /** + * Weight of the product, which can be used when calculating shipping costs. This is based on the unit set on the store + */ + weight?: number + /** + * Width of the product, which can be used when calculating shipping costs. + */ + width?: number + /** + * Depth of the product, which can be used when calculating shipping costs. + */ + depth?: number + /** + * Height of the product, which can be used when calculating shipping costs. + */ + height?: number + /** + * The price of the product. The price should include or exclude tax, based on the store settings. + */ + price?: number + /** + * The cost price of the product. Stored for reference only; it is not used or displayed anywhere on the store. + */ + cost_price?: number + /** + * The retail cost of the product. If entered, the retail cost price will be shown on the product page. + */ + retail_price?: number + /** + * If entered, the sale price will be used instead of value in the price field when calculating the product's cost. + */ + sale_price?: number + /** + * The ID of the tax class applied to the product. (NOTE: Value ignored if automatic tax is enabled.) + */ + tax_class_id?: number + /** + * Accepts AvaTax System Tax Codes, which identify products and services that fall into special sales-tax categories. By using these codes, merchants who subscribe to BigCommerce's Avalara Premium integration can calculate sales taxes more accurately. Stores without Avalara Premium will ignore the code when calculating sales tax. Do not pass more than one code. The codes are case-sensitive. For details, please see Avalara's documentation. + */ + product_tax_code?: string + /** + * An array of IDs for the categories to which this product belongs. When updating a product, if an array of categories is supplied, all product categories will be overwritten. Does not accept more than 1,000 ID values. + */ + categories?: number[] + /** + * A product can be added to an existing brand during a product /PUT or /POST. + */ + brand_id?: number + /** + * Current inventory level of the product. Simple inventory tracking must be enabled (See the `inventory_tracking` field) for this to take any effect. + */ + inventory_level?: number + /** + * Inventory warning level for the product. When the product's inventory level drops below the warning level, the store owner will be informed. Simple inventory tracking must be enabled (see the `inventory_tracking` field) for this to take any effect. + */ + inventory_warning_level?: number + /** + * The type of inventory tracking for the product. Values are: `none` - inventory levels will not be tracked; `product` - inventory levels will be tracked using the `inventory_level` and `inventory_warning_level` fields; `variant` - inventory levels will be tracked based on variants, which maintain their own warning levels and inventory levels. + */ + inventory_tracking?: 'none' | 'product' | 'variant' + /** + * A fixed shipping cost for the product. If defined, this value will be used during checkout instead of normal shipping-cost calculation. + */ + fixed_cost_shipping_price?: number + /** + * Flag used to indicate whether the product has free shipping. If `true`, the shipping cost for the product will be zero. + */ + is_free_shipping?: boolean + /** + * Flag to determine whether the product should be displayed to customers browsing the store. If `true`, the product will be displayed. If `false`, the product will be hidden from view. + */ + is_visible?: boolean + /** + * Flag to determine whether the product should be included in the `featured products` panel when viewing the store. + */ + is_featured?: boolean + /** + * An array of IDs for the related products. + */ + related_products?: number[] + /** + * Warranty information displayed on the product page. Can include HTML formatting. + */ + warranty?: string + /** + * The BIN picking number for the product. + */ + bin_picking_number?: string + /** + * The layout template file used to render this product category. This field is writable only for stores with a Blueprint theme applied. + */ + layout_file?: string + /** + * The product UPC code, which is used in feeds for shopping comparison sites and external channel integrations. + */ + upc?: string + /** + * A comma-separated list of keywords that can be used to locate the product when searching the store. + */ + search_keywords?: string + /** + * Availability of the product. Availability options are: `available` - the product can be purchased on the storefront; `disabled` - the product is listed in the storefront, but cannot be purchased; `preorder` - the product is listed for pre-orders. + */ + availability?: 'available' | 'disabled' | 'preorder' + /** + * Availability text displayed on the checkout page, under the product title. Tells the customer how long it will normally take to ship this product, such as: 'Usually ships in 24 hours.' + */ + availability_description?: string + /** + * Type of gift-wrapping options. Values: `any` - allow any gift-wrapping options in the store; `none` - disallow gift-wrapping on the product; `list` – provide a list of IDs in the `gift_wrapping_options_list` field. + */ + gift_wrapping_options_type?: 'any' | 'none' | 'list' + /** + * A list of gift-wrapping option IDs. + */ + gift_wrapping_options_list?: number[] + /** + * Priority to give this product when included in product lists on category pages and in search results. Lower integers will place the product closer to the top of the results. + */ + sort_order?: number + /** + * The product condition. Will be shown on the product page if the `is_condition_shown` field's value is `true`. Possible values: `New`, `Used`, `Refurbished`. + */ + condition?: 'New' | 'Used' | 'Refurbished' + /** + * Flag used to determine whether the product condition is shown to the customer on the product page. + */ + is_condition_shown?: boolean + /** + * The minimum quantity an order must contain, to be eligible to purchase this product. + */ + order_quantity_minimum?: number + /** + * The maximum quantity an order can contain when purchasing the product. + */ + order_quantity_maximum?: number + /** + * Custom title for the product page. If not defined, the product name will be used as the meta title. + */ + page_title?: string + /** + * Custom meta keywords for the product page. If not defined, the store's default keywords will be used. + */ + meta_keywords?: string[] + /** + * Custom meta description for the product page. If not defined, the store's default meta description will be used. + */ + meta_description?: string + /** + * The number of times the product has been viewed. + */ + view_count?: number + /** + * Pre-order release date. See the `availability` field for details on setting a product's availability to accept pre-orders. + */ + preorder_release_date?: string + /** + * Custom expected-date message to display on the product page. If undefined, the message defaults to the storewide setting. Can contain the `%%DATE%%` placeholder, which will be substituted for the release date. + */ + preorder_message?: string + /** + * If set to true then on the preorder release date the preorder status will automatically be removed. + * If set to false, then on the release date the preorder status **will not** be removed. It will need to be changed manually either in the + * control panel or using the API. Using the API set `availability` to `available`. + */ + is_preorder_only?: boolean + /** + * False by default, indicating that this product's price should be shown on the product page. If set to `true`, the price is hidden. (NOTE: To successfully set `is_price_hidden` to `true`, the `availability` value must be `disabled`.) + */ + is_price_hidden?: boolean + /** + * By default, an empty string. If `is_price_hidden` is `true`, the value of `price_hidden_label` is displayed instead of the price. (NOTE: To successfully set a non-empty string value with `is_price_hidden` set to `true`, the `availability` value must be `disabled`.) + */ + price_hidden_label?: string + custom_url?: definitions['customUrl_Full'] + /** + * Type of product, defaults to `product`. + */ + open_graph_type?: + | 'product' + | 'album' + | 'book' + | 'drink' + | 'food' + | 'game' + | 'movie' + | 'song' + | 'tv_show' + /** + * Title of the product, if not specified the product name will be used instead. + */ + open_graph_title?: string + /** + * Description to use for the product, if not specified then the meta_description will be used instead. + */ + open_graph_description?: string + /** + * Flag to determine if product description or open graph description is used. + */ + open_graph_use_meta_description?: boolean + /** + * Flag to determine if product name or open graph name is used. + */ + open_graph_use_product_name?: boolean + /** + * Flag to determine if product image or open graph image is used. + */ + open_graph_use_image?: boolean + /** + * The brand can be created during a product PUT or POST request. If the brand already exists then the product will be added. If not the brand will be created and the product added. If using `brand_name` it performs a fuzzy match and adds the brand. eg. "Common Good" and "Common good" are the same. Brand name does not return as part of a product response. Only the `brand_id`. + */ + 'brand_name or brand_id'?: string + /** + * Global Trade Item Number + */ + gtin?: string + /** + * Manufacturer Part Number + */ + mpn?: string + /** + * The total rating for the product. + */ + reviews_rating_sum?: number + /** + * The number of times the product has been rated. + */ + reviews_count?: number + /** + * The total quantity of this product sold. + */ + total_sold?: number + custom_fields?: definitions['productCustomField_Put'][] + bulk_pricing_rules?: definitions['bulkPricingRule_Full'][] + images?: definitions['productImage_Full'][] + primary_image?: definitions['productImage_Full'] + videos?: definitions['productVideo_Full'][] + } + /** + * Properties for updating metafields. + */ + metafield_Put: { + /** + * Unique ID of the *Metafield*. Read-Only. + */ + id?: number + } & definitions['metafield_Base'] + metafield_Full: definitions['metafield_Put'] & { + /** + * Date and time of the metafield's creation. Read-Only. + */ + date_created?: string + /** + * Date and time when the metafield was last updated. Read-Only. + */ + date_modified?: string + } + /** + * The model for a PUT to update variants on a product. + */ + productVariant_Put: definitions['productVariant_Base'] & { + product_id?: number + sku?: string + } +} diff --git a/framework/bigcommerce/api/definitions/store-content.ts b/framework/bigcommerce/api/definitions/store-content.ts new file mode 100644 index 00000000..f00c2884 --- /dev/null +++ b/framework/bigcommerce/api/definitions/store-content.ts @@ -0,0 +1,329 @@ +/** + * This file was auto-generated by swagger-to-ts. + * Do not make direct changes to the file. + */ + +export interface definitions { + blogPost_Full: { + /** + * ID of this blog post. (READ-ONLY) + */ + id?: number + } & definitions['blogPost_Base'] + addresses: { + /** + * Full URL of where the resource is located. + */ + url?: string + /** + * Resource being accessed. + */ + resource?: string + } + formField: { + /** + * Name of the form field + */ + name?: string + /** + * Value of the form field + */ + value?: string + } + page_Full: { + /** + * ID of the page. + */ + id?: number + } & definitions['page_Base'] + redirect: { + /** + * Numeric ID of the redirect. + */ + id?: number + /** + * The path from which to redirect. + */ + path: string + forward: definitions['forward'] + /** + * URL of the redirect. READ-ONLY + */ + url?: string + } + forward: { + /** + * The type of redirect. If it is a `manual` redirect then type will always be manual. Dynamic redirects will have the type of the page. Such as product or category. + */ + type?: string + /** + * Reference of the redirect. Dynamic redirects will have the category or product number. Manual redirects will have the url that is being directed to. + */ + ref?: number + } + customer_Full: { + /** + * Unique numeric ID of this customer. This is a READ-ONLY field; do not set or modify its value in a POST or PUT request. + */ + id?: number + /** + * Not returned in any responses, but accepts up to two fields allowing you to set the customer’s password. If a password is not supplied, it is generated automatically. For further information about using this object, please see the Customers resource documentation. + */ + _authentication?: { + force_reset?: string + password?: string + password_confirmation?: string + } + /** + * The name of the company for which the customer works. + */ + company?: string + /** + * First name of the customer. + */ + first_name: string + /** + * Last name of the customer. + */ + last_name: string + /** + * Email address of the customer. + */ + email: string + /** + * Phone number of the customer. + */ + phone?: string + /** + * Date on which the customer registered from the storefront or was created in the control panel. This is a READ-ONLY field; do not set or modify its value in a POST or PUT request. + */ + date_created?: string + /** + * Date on which the customer updated their details in the storefront or was updated in the control panel. This is a READ-ONLY field; do not set or modify its value in a POST or PUT request. + */ + date_modified?: string + /** + * The amount of credit the customer has. (Float, Float as String, Integer) + */ + store_credit?: string + /** + * The customer’s IP address when they signed up. + */ + registration_ip_address?: string + /** + * The group to which the customer belongs. + */ + customer_group_id?: number + /** + * Store-owner notes on the customer. + */ + notes?: string + /** + * Used to identify customers who fall into special sales-tax categories – in particular, those who are fully or partially exempt from paying sales tax. Can be blank, or can contain a single AvaTax code. (The codes are case-sensitive.) Stores that subscribe to BigCommerce’s Avalara Premium integration will use this code to determine how/whether to apply sales tax. Does not affect sales-tax calculations for stores that do not subscribe to Avalara Premium. + */ + tax_exempt_category?: string + /** + * Records whether the customer would like to receive marketing content from this store. READ-ONLY.This is a READ-ONLY field; do not set or modify its value in a POST or PUT request. + */ + accepts_marketing?: boolean + addresses?: definitions['addresses'] + /** + * Array of custom fields. This is a READ-ONLY field; do not set or modify its value in a POST or PUT request. + */ + form_fields?: definitions['formField'][] + /** + * Force a password change on next login. + */ + reset_pass_on_login?: boolean + } + categoryAccessLevel: { + /** + * + `all` - Customers can access all categories + * + `specific` - Customers can access a specific list of categories + * + `none` - Customers are prevented from viewing any of the categories in this group. + */ + type?: 'all' | 'specific' | 'none' + /** + * Is an array of category IDs and should be supplied only if `type` is specific. + */ + categories?: string[] + } + timeZone: { + /** + * a string identifying the time zone, in the format: /. + */ + name?: string + /** + * a negative or positive number, identifying the offset from UTC/GMT, in seconds, during winter/standard time. + */ + raw_offset?: number + /** + * "-/+" offset from UTC/GMT, in seconds, during summer/daylight saving time. + */ + dst_offset?: number + /** + * a boolean indicating whether this time zone observes daylight saving time. + */ + dst_correction?: boolean + date_format?: definitions['dateFormat'] + } + count_Response: { count?: number } + dateFormat: { + /** + * string that defines dates’ display format, in the pattern: M jS Y + */ + display?: string + /** + * string that defines the CSV export format for orders, customers, and products, in the pattern: M jS Y + */ + export?: string + /** + * string that defines dates’ extended-display format, in the pattern: M jS Y @ g:i A. + */ + extended_display?: string + } + blogTags: { tag?: string; post_ids?: number[] }[] + blogPost_Base: { + /** + * Title of this blog post. + */ + title: string + /** + * URL for the public blog post. + */ + url?: string + /** + * URL to preview the blog post. (READ-ONLY) + */ + preview_url?: string + /** + * Text body of the blog post. + */ + body: string + /** + * Tags to characterize the blog post. + */ + tags?: string[] + /** + * Summary of the blog post. (READ-ONLY) + */ + summary?: string + /** + * Whether the blog post is published. + */ + is_published?: boolean + published_date?: definitions['publishedDate'] + /** + * Published date in `ISO 8601` format. + */ + published_date_iso8601?: string + /** + * Description text for this blog post’s `` element. + */ + meta_description?: string + /** + * Keywords for this blog post’s `` element. + */ + meta_keywords?: string + /** + * Name of the blog post’s author. + */ + author?: string + /** + * Local path to a thumbnail uploaded to `product_images/` via [WebDav](https://support.bigcommerce.com/s/article/File-Access-WebDAV). + */ + thumbnail_path?: string + } + publishedDate: { timezone_type?: string; date?: string; timezone?: string } + /** + * Not returned in any responses, but accepts up to two fields allowing you to set the customer’s password. If a password is not supplied, it is generated automatically. For further information about using this object, please see the Customers resource documentation. + */ + authentication: { + force_reset?: string + password?: string + password_confirmation?: string + } + customer_Base: { [key: string]: any } + page_Base: { + /** + * ID of any parent Web page. + */ + parent_id?: number + /** + * `page`: free-text page + * `link`: link to another web address + * `rss_feed`: syndicated content from an RSS feed + * `contact_form`: When the store's contact form is used. + */ + type: 'page' | 'rss_feed' | 'contact_form' | 'raw' | 'link' + /** + * Where the page’s type is a contact form: object whose members are the fields enabled (in the control panel) for storefront display. Possible members are:`fullname`: full name of the customer submitting the form; `phone`: customer’s phone number, as submitted on the form; `companyname`: customer’s submitted company name; `orderno`: customer’s submitted order number; `rma`: customer’s submitted RMA (Return Merchandise Authorization) number. + */ + contact_fields?: string + /** + * Where the page’s type is a contact form: email address that receives messages sent via the form. + */ + email?: string + /** + * Page name, as displayed on the storefront. + */ + name: string + /** + * Relative URL on the storefront for this page. + */ + url?: string + /** + * Description contained within this page’s `` element. + */ + meta_description?: string + /** + * HTML or variable that populates this page’s `` element, in default/desktop view. Required in POST if page type is `raw`. + */ + body: string + /** + * HTML to use for this page's body when viewed in the mobile template (deprecated). + */ + mobile_body?: string + /** + * If true, this page has a mobile version. + */ + has_mobile_version?: boolean + /** + * If true, this page appears in the storefront’s navigation menu. + */ + is_visible?: boolean + /** + * If true, this page is the storefront’s home page. + */ + is_homepage?: boolean + /** + * Text specified for this page’s `` element. (If empty, the value of the name property is used.) + */ + meta_title?: string + /** + * Layout template for this page. This field is writable only for stores with a Blueprint theme applied. + */ + layout_file?: string + /** + * Order in which this page should display on the storefront. (Lower integers specify earlier display.) + */ + sort_order?: number + /** + * Comma-separated list of keywords that shoppers can use to locate this page when searching the store. + */ + search_keywords?: string + /** + * Comma-separated list of SEO-relevant keywords to include in the page’s `<meta/>` element. + */ + meta_keywords?: string + /** + * If page type is `rss_feed` the n this field is visisble. Required in POST required for `rss page` type. + */ + feed: string + /** + * If page type is `link` this field is returned. Required in POST to create a `link` page. + */ + link: string + content_type?: 'application/json' | 'text/javascript' | 'text/html' + } +} diff --git a/framework/bigcommerce/api/definitions/wishlist.ts b/framework/bigcommerce/api/definitions/wishlist.ts new file mode 100644 index 00000000..6ec21c10 --- /dev/null +++ b/framework/bigcommerce/api/definitions/wishlist.ts @@ -0,0 +1,142 @@ +/** + * This file was auto-generated by swagger-to-ts. + * Do not make direct changes to the file. + */ + +export interface definitions { + wishlist_Post: { + /** + * The customer id. + */ + customer_id: number + /** + * Whether the wishlist is available to the public. + */ + is_public?: boolean + /** + * The title of the wishlist. + */ + name?: string + /** + * Array of Wishlist items. + */ + items?: { + /** + * The ID of the product. + */ + product_id?: number + /** + * The variant ID of the product. + */ + variant_id?: number + }[] + } + wishlist_Put: { + /** + * The customer id. + */ + customer_id: number + /** + * Whether the wishlist is available to the public. + */ + is_public?: boolean + /** + * The title of the wishlist. + */ + name?: string + /** + * Array of Wishlist items. + */ + items?: { + /** + * The ID of the item + */ + id?: number + /** + * The ID of the product. + */ + product_id?: number + /** + * The variant ID of the item. + */ + variant_id?: number + }[] + } + wishlist_Full: { + /** + * Wishlist ID, provided after creating a wishlist with a POST. + */ + id?: number + /** + * The ID the customer to which the wishlist belongs. + */ + customer_id?: number + /** + * The Wishlist's name. + */ + name?: string + /** + * Whether the Wishlist is available to the public. + */ + is_public?: boolean + /** + * The token of the Wishlist. This is created internally within BigCommerce. The Wishlist ID is to be used for external apps. Read-Only + */ + token?: string + /** + * Array of Wishlist items + */ + items?: definitions['wishlistItem_Full'][] + } + wishlistItem_Full: { + /** + * The ID of the item + */ + id?: number + /** + * The ID of the product. + */ + product_id?: number + /** + * The variant ID of the item. + */ + variant_id?: number + } + wishlistItem_Post: { + /** + * The ID of the product. + */ + product_id?: number + /** + * The variant ID of the product. + */ + variant_id?: number + } + /** + * Data about the response, including pagination and collection totals. + */ + pagination: { + /** + * Total number of items in the result set. + */ + total?: number + /** + * Total number of items in the collection response. + */ + count?: number + /** + * The amount of items returned in the collection per page, controlled by the limit parameter. + */ + per_page?: number + /** + * The page you are currently on within the collection. + */ + current_page?: number + /** + * The total number of pages in the collection. + */ + total_pages?: number + } + error: { status?: number; title?: string; type?: string } + metaCollection: { pagination?: definitions['pagination'] } +} diff --git a/framework/bigcommerce/api/fragments/category-tree.ts b/framework/bigcommerce/api/fragments/category-tree.ts new file mode 100644 index 00000000..e26f1719 --- /dev/null +++ b/framework/bigcommerce/api/fragments/category-tree.ts @@ -0,0 +1,9 @@ +export const categoryTreeItemFragment = /* GraphQL */ ` + fragment categoryTreeItem on CategoryTreeItem { + entityId + name + path + description + productCount + } +` diff --git a/framework/bigcommerce/api/fragments/product.ts b/framework/bigcommerce/api/fragments/product.ts new file mode 100644 index 00000000..d266b8c9 --- /dev/null +++ b/framework/bigcommerce/api/fragments/product.ts @@ -0,0 +1,113 @@ +export const productPrices = /* GraphQL */ ` + fragment productPrices on Prices { + price { + value + currencyCode + } + salePrice { + value + currencyCode + } + retailPrice { + value + currencyCode + } + } +` + +export const swatchOptionFragment = /* GraphQL */ ` + fragment swatchOption on SwatchOptionValue { + isDefault + hexColors + } +` + +export const multipleChoiceOptionFragment = /* GraphQL */ ` + fragment multipleChoiceOption on MultipleChoiceOption { + values { + edges { + node { + label + ...swatchOption + } + } + } + } + + ${swatchOptionFragment} +` + +export const productInfoFragment = /* GraphQL */ ` + fragment productInfo on Product { + entityId + name + path + brand { + entityId + } + description + prices { + ...productPrices + } + images { + edges { + node { + urlOriginal + altText + isDefault + } + } + } + variants { + edges { + node { + entityId + defaultImage { + urlOriginal + altText + isDefault + } + } + } + } + productOptions { + edges { + node { + __typename + entityId + displayName + ...multipleChoiceOption + } + } + } + localeMeta: metafields(namespace: $locale, keys: ["name", "description"]) + @include(if: $hasLocale) { + edges { + node { + key + value + } + } + } + } + + ${productPrices} + ${multipleChoiceOptionFragment} +` + +export const productConnectionFragment = /* GraphQL */ ` + fragment productConnnection on ProductConnection { + pageInfo { + startCursor + endCursor + } + edges { + cursor + node { + ...productInfo + } + } + } + + ${productInfoFragment} +` diff --git a/framework/bigcommerce/api/index.ts b/framework/bigcommerce/api/index.ts new file mode 100644 index 00000000..0216fe61 --- /dev/null +++ b/framework/bigcommerce/api/index.ts @@ -0,0 +1,88 @@ +import type { RequestInit } from '@vercel/fetch' +import type { CommerceAPIConfig } from '@commerce/api' +import fetchGraphqlApi from './utils/fetch-graphql-api' +import fetchStoreApi from './utils/fetch-store-api' + +export interface BigcommerceConfig extends CommerceAPIConfig { + // Indicates if the returned metadata with translations should be applied to the + // data or returned as it is + applyLocale?: boolean + storeApiUrl: string + storeApiToken: string + storeApiClientId: string + storeChannelId?: string + storeApiFetch<T>(endpoint: string, options?: RequestInit): Promise<T> +} + +const API_URL = process.env.BIGCOMMERCE_STOREFRONT_API_URL +const API_TOKEN = process.env.BIGCOMMERCE_STOREFRONT_API_TOKEN +const STORE_API_URL = process.env.BIGCOMMERCE_STORE_API_URL +const STORE_API_TOKEN = process.env.BIGCOMMERCE_STORE_API_TOKEN +const STORE_API_CLIENT_ID = process.env.BIGCOMMERCE_STORE_API_CLIENT_ID +const STORE_CHANNEL_ID = process.env.BIGCOMMERCE_CHANNEL_ID + +if (!API_URL) { + throw new Error( + `The environment variable BIGCOMMERCE_STOREFRONT_API_URL is missing and it's required to access your store` + ) +} + +if (!API_TOKEN) { + throw new Error( + `The environment variable BIGCOMMERCE_STOREFRONT_API_TOKEN is missing and it's required to access your store` + ) +} + +if (!(STORE_API_URL && STORE_API_TOKEN && STORE_API_CLIENT_ID)) { + throw new Error( + `The environment variables BIGCOMMERCE_STORE_API_URL, BIGCOMMERCE_STORE_API_TOKEN, BIGCOMMERCE_STORE_API_CLIENT_ID have to be set in order to access the REST API of your store` + ) +} + +export class Config { + private config: BigcommerceConfig + + constructor(config: Omit<BigcommerceConfig, 'customerCookie'>) { + this.config = { + ...config, + // The customerCookie is not customizable for now, BC sets the cookie and it's + // not important to rename it + customerCookie: 'SHOP_TOKEN', + } + } + + getConfig(userConfig: Partial<BigcommerceConfig> = {}) { + return Object.entries(userConfig).reduce<BigcommerceConfig>( + (cfg, [key, value]) => Object.assign(cfg, { [key]: value }), + { ...this.config } + ) + } + + setConfig(newConfig: Partial<BigcommerceConfig>) { + Object.assign(this.config, newConfig) + } +} + +const ONE_DAY = 60 * 60 * 24 +const config = new Config({ + commerceUrl: API_URL, + apiToken: API_TOKEN, + cartCookie: process.env.BIGCOMMERCE_CART_COOKIE ?? 'bc_cartId', + cartCookieMaxAge: ONE_DAY * 30, + fetch: fetchGraphqlApi, + applyLocale: true, + // REST API only + storeApiUrl: STORE_API_URL, + storeApiToken: STORE_API_TOKEN, + storeApiClientId: STORE_API_CLIENT_ID, + storeChannelId: STORE_CHANNEL_ID, + storeApiFetch: fetchStoreApi, +}) + +export function getConfig(userConfig?: Partial<BigcommerceConfig>) { + return config.getConfig(userConfig) +} + +export function setConfig(newConfig: Partial<BigcommerceConfig>) { + return config.setConfig(newConfig) +} diff --git a/framework/bigcommerce/api/utils/concat-cookie.ts b/framework/bigcommerce/api/utils/concat-cookie.ts new file mode 100644 index 00000000..362e12e9 --- /dev/null +++ b/framework/bigcommerce/api/utils/concat-cookie.ts @@ -0,0 +1,14 @@ +type Header = string | number | string[] | undefined + +export default function concatHeader(prev: Header, val: Header) { + if (!val) return prev + if (!prev) return val + + if (Array.isArray(prev)) return prev.concat(String(val)) + + prev = String(prev) + + if (Array.isArray(val)) return [prev].concat(val) + + return [prev, String(val)] +} diff --git a/framework/bigcommerce/api/utils/create-api-handler.ts b/framework/bigcommerce/api/utils/create-api-handler.ts new file mode 100644 index 00000000..315ec464 --- /dev/null +++ b/framework/bigcommerce/api/utils/create-api-handler.ts @@ -0,0 +1,58 @@ +import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next' +import { BigcommerceConfig, getConfig } from '..' + +export type BigcommerceApiHandler< + T = any, + H extends BigcommerceHandlers = {}, + Options extends {} = {} +> = ( + req: NextApiRequest, + res: NextApiResponse<BigcommerceApiResponse<T>>, + config: BigcommerceConfig, + handlers: H, + // Custom configs that may be used by a particular handler + options: Options +) => void | Promise<void> + +export type BigcommerceHandler<T = any, Body = null> = (options: { + req: NextApiRequest + res: NextApiResponse<BigcommerceApiResponse<T>> + config: BigcommerceConfig + body: Body +}) => void | Promise<void> + +export type BigcommerceHandlers<T = any> = { + [k: string]: BigcommerceHandler<T, any> +} + +export type BigcommerceApiResponse<T> = { + data: T | null + errors?: { message: string; code?: string }[] +} + +export default function createApiHandler< + T = any, + H extends BigcommerceHandlers = {}, + Options extends {} = {} +>( + handler: BigcommerceApiHandler<T, H, Options>, + handlers: H, + defaultOptions: Options +) { + return function getApiHandler({ + config, + operations, + options, + }: { + config?: BigcommerceConfig + operations?: Partial<H> + options?: Options extends {} ? Partial<Options> : never + } = {}): NextApiHandler { + const ops = { ...operations, ...handlers } + const opts = { ...defaultOptions, ...options } + + return function apiHandler(req, res) { + return handler(req, res, getConfig(config), ops, opts) + } + } +} diff --git a/framework/bigcommerce/api/utils/errors.ts b/framework/bigcommerce/api/utils/errors.ts new file mode 100644 index 00000000..77e2007f --- /dev/null +++ b/framework/bigcommerce/api/utils/errors.ts @@ -0,0 +1,25 @@ +import type { Response } from '@vercel/fetch' + +// Used for GraphQL errors +export class BigcommerceGraphQLError extends Error {} + +export class BigcommerceApiError extends Error { + status: number + res: Response + data: any + + constructor(msg: string, res: Response, data?: any) { + super(msg) + this.name = 'BigcommerceApiError' + this.status = res.status + this.res = res + this.data = data + } +} + +export class BigcommerceNetworkError extends Error { + constructor(msg: string) { + super(msg) + this.name = 'BigcommerceNetworkError' + } +} diff --git a/framework/bigcommerce/api/utils/fetch-graphql-api.ts b/framework/bigcommerce/api/utils/fetch-graphql-api.ts new file mode 100644 index 00000000..a449b81e --- /dev/null +++ b/framework/bigcommerce/api/utils/fetch-graphql-api.ts @@ -0,0 +1,38 @@ +import { FetcherError } from '@commerce/utils/errors' +import type { GraphQLFetcher } from '@commerce/api' +import { getConfig } from '..' +import fetch from './fetch' + +const fetchGraphqlApi: GraphQLFetcher = async ( + query: string, + { variables, preview } = {}, + fetchOptions +) => { + // log.warn(query) + const config = getConfig() + const res = await fetch(config.commerceUrl + (preview ? '/preview' : ''), { + ...fetchOptions, + method: 'POST', + headers: { + Authorization: `Bearer ${config.apiToken}`, + ...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 Bigcommerce API' }], + status: res.status, + }) + } + + return { data: json.data, res } +} + +export default fetchGraphqlApi diff --git a/framework/bigcommerce/api/utils/fetch-store-api.ts b/framework/bigcommerce/api/utils/fetch-store-api.ts new file mode 100644 index 00000000..7e59b9f0 --- /dev/null +++ b/framework/bigcommerce/api/utils/fetch-store-api.ts @@ -0,0 +1,71 @@ +import type { RequestInit, Response } from '@vercel/fetch' +import { getConfig } from '..' +import { BigcommerceApiError, BigcommerceNetworkError } from './errors' +import fetch from './fetch' + +export default async function fetchStoreApi<T>( + endpoint: string, + options?: RequestInit +): Promise<T> { + const config = getConfig() + let res: Response + + try { + res = await fetch(config.storeApiUrl + endpoint, { + ...options, + headers: { + ...options?.headers, + 'Content-Type': 'application/json', + 'X-Auth-Token': config.storeApiToken, + 'X-Auth-Client': config.storeApiClientId, + }, + }) + } catch (error) { + throw new BigcommerceNetworkError( + `Fetch to Bigcommerce failed: ${error.message}` + ) + } + + const contentType = res.headers.get('Content-Type') + const isJSON = contentType?.includes('application/json') + + if (!res.ok) { + const data = isJSON ? await res.json() : await getTextOrNull(res) + const headers = getRawHeaders(res) + const msg = `Big Commerce API error (${ + res.status + }) \nHeaders: ${JSON.stringify(headers, null, 2)}\n${ + typeof data === 'string' ? data : JSON.stringify(data, null, 2) + }` + + throw new BigcommerceApiError(msg, res, data) + } + + if (res.status !== 204 && !isJSON) { + throw new BigcommerceApiError( + `Fetch to Bigcommerce API failed, expected JSON content but found: ${contentType}`, + res + ) + } + + // If something was removed, the response will be empty + return res.status === 204 ? null : await res.json() +} + +function getRawHeaders(res: Response) { + const headers: { [key: string]: string } = {} + + res.headers.forEach((value, key) => { + headers[key] = value + }) + + return headers +} + +function getTextOrNull(res: Response) { + try { + return res.text() + } catch (err) { + return null + } +} diff --git a/framework/bigcommerce/api/utils/fetch.ts b/framework/bigcommerce/api/utils/fetch.ts new file mode 100644 index 00000000..9d9fff3e --- /dev/null +++ b/framework/bigcommerce/api/utils/fetch.ts @@ -0,0 +1,3 @@ +import zeitFetch from '@vercel/fetch' + +export default zeitFetch() diff --git a/framework/bigcommerce/api/utils/filter-edges.ts b/framework/bigcommerce/api/utils/filter-edges.ts new file mode 100644 index 00000000..09cd2064 --- /dev/null +++ b/framework/bigcommerce/api/utils/filter-edges.ts @@ -0,0 +1,5 @@ +export default function filterEdges<T>( + edges: (T | null | undefined)[] | null | undefined +) { + return edges?.filter((edge): edge is T => !!edge) ?? [] +} diff --git a/framework/bigcommerce/api/utils/get-cart-cookie.ts b/framework/bigcommerce/api/utils/get-cart-cookie.ts new file mode 100644 index 00000000..7ca6cd5e --- /dev/null +++ b/framework/bigcommerce/api/utils/get-cart-cookie.ts @@ -0,0 +1,20 @@ +import { serialize, CookieSerializeOptions } from 'cookie' + +export default function getCartCookie( + name: string, + cartId?: string, + maxAge?: number +) { + const options: CookieSerializeOptions = + cartId && maxAge + ? { + maxAge, + expires: new Date(Date.now() + maxAge * 1000), + secure: process.env.NODE_ENV === 'production', + path: '/', + sameSite: 'lax', + } + : { maxAge: -1, path: '/' } // Removes the cookie + + return serialize(name, cartId || '', options) +} diff --git a/framework/bigcommerce/api/utils/is-allowed-method.ts b/framework/bigcommerce/api/utils/is-allowed-method.ts new file mode 100644 index 00000000..78bbba56 --- /dev/null +++ b/framework/bigcommerce/api/utils/is-allowed-method.ts @@ -0,0 +1,28 @@ +import type { NextApiRequest, NextApiResponse } from 'next' + +export default function isAllowedMethod( + req: NextApiRequest, + res: NextApiResponse, + allowedMethods: string[] +) { + const methods = allowedMethods.includes('OPTIONS') + ? allowedMethods + : [...allowedMethods, 'OPTIONS'] + + if (!req.method || !methods.includes(req.method)) { + res.status(405) + res.setHeader('Allow', methods.join(', ')) + res.end() + return false + } + + if (req.method === 'OPTIONS') { + res.status(200) + res.setHeader('Allow', methods.join(', ')) + res.setHeader('Content-Length', '0') + res.end() + return false + } + + return true +} diff --git a/framework/bigcommerce/api/utils/parse-item.ts b/framework/bigcommerce/api/utils/parse-item.ts new file mode 100644 index 00000000..7c8cd472 --- /dev/null +++ b/framework/bigcommerce/api/utils/parse-item.ts @@ -0,0 +1,28 @@ +import type { ItemBody as WishlistItemBody } from '../wishlist' +import type { CartItemBody, OptionSelections } from '../../types' + +type BCWishlistItemBody = { + product_id: number + variant_id: number +} + +type BCCartItemBody = { + product_id: number + variant_id: number + quantity?: number + option_selections?: OptionSelections +} + +export const parseWishlistItem = ( + item: WishlistItemBody +): BCWishlistItemBody => ({ + product_id: Number(item.productId), + variant_id: Number(item.variantId), +}) + +export const parseCartItem = (item: CartItemBody): BCCartItemBody => ({ + quantity: item.quantity, + product_id: Number(item.productId), + variant_id: Number(item.variantId), + option_selections: item.optionSelections, +}) diff --git a/framework/bigcommerce/api/utils/set-product-locale-meta.ts b/framework/bigcommerce/api/utils/set-product-locale-meta.ts new file mode 100644 index 00000000..974a197b --- /dev/null +++ b/framework/bigcommerce/api/utils/set-product-locale-meta.ts @@ -0,0 +1,21 @@ +import type { ProductNode } from '../../product/get-all-products' +import type { RecursivePartial } from './types' + +export default function setProductLocaleMeta( + node: RecursivePartial<ProductNode> +) { + if (node.localeMeta?.edges) { + node.localeMeta.edges = node.localeMeta.edges.filter((edge) => { + const { key, value } = edge?.node ?? {} + if (key && key in node) { + ;(node as any)[key] = value + return false + } + return true + }) + + if (!node.localeMeta.edges.length) { + delete node.localeMeta + } + } +} diff --git a/framework/bigcommerce/api/utils/types.ts b/framework/bigcommerce/api/utils/types.ts new file mode 100644 index 00000000..56f9c172 --- /dev/null +++ b/framework/bigcommerce/api/utils/types.ts @@ -0,0 +1,7 @@ +export type RecursivePartial<T> = { + [P in keyof T]?: RecursivePartial<T[P]> +} + +export type RecursiveRequired<T> = { + [P in keyof T]-?: RecursiveRequired<T[P]> +} diff --git a/framework/bigcommerce/api/wishlist/handlers/add-item.ts b/framework/bigcommerce/api/wishlist/handlers/add-item.ts new file mode 100644 index 00000000..00d7b06b --- /dev/null +++ b/framework/bigcommerce/api/wishlist/handlers/add-item.ts @@ -0,0 +1,56 @@ +import type { WishlistHandlers } from '..' +import getCustomerId from '../../../customer/get-customer-id' +import getCustomerWishlist from '../../../customer/get-customer-wishlist' +import { parseWishlistItem } from '../../utils/parse-item' + +// Returns the wishlist of the signed customer +const addItem: WishlistHandlers['addItem'] = async ({ + res, + body: { customerToken, item }, + config, +}) => { + if (!item) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Missing item' }], + }) + } + + const customerId = + customerToken && (await getCustomerId({ customerToken, config })) + + if (!customerId) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const { wishlist } = await getCustomerWishlist({ + variables: { customerId }, + config, + }) + const options = { + method: 'POST', + body: JSON.stringify( + wishlist + ? { + items: [parseWishlistItem(item)], + } + : { + name: 'Wishlist', + customer_id: customerId, + items: [parseWishlistItem(item)], + is_public: false, + } + ), + } + + const { data } = wishlist + ? await config.storeApiFetch(`/v3/wishlists/${wishlist.id}/items`, options) + : await config.storeApiFetch('/v3/wishlists', options) + + res.status(200).json({ data }) +} + +export default addItem diff --git a/framework/bigcommerce/api/wishlist/handlers/get-wishlist.ts b/framework/bigcommerce/api/wishlist/handlers/get-wishlist.ts new file mode 100644 index 00000000..3737c033 --- /dev/null +++ b/framework/bigcommerce/api/wishlist/handlers/get-wishlist.ts @@ -0,0 +1,37 @@ +import getCustomerId from '../../../customer/get-customer-id' +import getCustomerWishlist from '../../../customer/get-customer-wishlist' +import type { Wishlist, WishlistHandlers } from '..' + +// Return wishlist info +const getWishlist: WishlistHandlers['getWishlist'] = async ({ + res, + body: { customerToken, includeProducts }, + config, +}) => { + let result: { data?: Wishlist } = {} + + if (customerToken) { + const customerId = + customerToken && (await getCustomerId({ customerToken, config })) + + if (!customerId) { + // If the customerToken is invalid, then this request is too + return res.status(404).json({ + data: null, + errors: [{ message: 'Wishlist not found' }], + }) + } + + const { wishlist } = await getCustomerWishlist({ + variables: { customerId }, + includeProducts, + config, + }) + + result = { data: wishlist } + } + + res.status(200).json({ data: result.data ?? null }) +} + +export default getWishlist diff --git a/framework/bigcommerce/api/wishlist/handlers/remove-item.ts b/framework/bigcommerce/api/wishlist/handlers/remove-item.ts new file mode 100644 index 00000000..a9cfd9db --- /dev/null +++ b/framework/bigcommerce/api/wishlist/handlers/remove-item.ts @@ -0,0 +1,39 @@ +import getCustomerId from '../../../customer/get-customer-id' +import getCustomerWishlist, { + Wishlist, +} from '../../../customer/get-customer-wishlist' +import type { WishlistHandlers } from '..' + +// Return current wishlist info +const removeItem: WishlistHandlers['removeItem'] = async ({ + res, + body: { customerToken, itemId }, + config, +}) => { + const customerId = + customerToken && (await getCustomerId({ customerToken, config })) + const { wishlist } = + (customerId && + (await getCustomerWishlist({ + variables: { customerId }, + config, + }))) || + {} + + if (!wishlist || !itemId) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const result = await config.storeApiFetch<{ data: Wishlist } | null>( + `/v3/wishlists/${wishlist.id}/items/${itemId}`, + { method: 'DELETE' } + ) + const data = result?.data ?? null + + res.status(200).json({ data }) +} + +export default removeItem diff --git a/framework/bigcommerce/api/wishlist/index.ts b/framework/bigcommerce/api/wishlist/index.ts new file mode 100644 index 00000000..7c700689 --- /dev/null +++ b/framework/bigcommerce/api/wishlist/index.ts @@ -0,0 +1,104 @@ +import isAllowedMethod from '../utils/is-allowed-method' +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import { BigcommerceApiError } from '../utils/errors' +import type { + Wishlist, + WishlistItem, +} from '../../customer/get-customer-wishlist' +import getWishlist from './handlers/get-wishlist' +import addItem from './handlers/add-item' +import removeItem from './handlers/remove-item' +import type { Product, ProductVariant, Customer } from '@commerce/types' + +export type { Wishlist, WishlistItem } + +export type ItemBody = { + productId: Product['id'] + variantId: ProductVariant['id'] +} + +export type AddItemBody = { item: ItemBody } + +export type RemoveItemBody = { itemId: Product['id'] } + +export type WishlistBody = { + customer_id: Customer['entityId'] + is_public: number + name: string + items: any[] +} + +export type AddWishlistBody = { wishlist: WishlistBody } + +export type WishlistHandlers = { + getWishlist: BigcommerceHandler< + Wishlist, + { customerToken?: string; includeProducts?: boolean } + > + addItem: BigcommerceHandler< + Wishlist, + { customerToken?: string } & Partial<AddItemBody> + > + removeItem: BigcommerceHandler< + Wishlist, + { customerToken?: string } & Partial<RemoveItemBody> + > +} + +const METHODS = ['GET', 'POST', 'DELETE'] + +// TODO: a complete implementation should have schema validation for `req.body` +const wishlistApi: BigcommerceApiHandler<Wishlist, WishlistHandlers> = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + const { cookies } = req + const customerToken = cookies[config.customerCookie] + + try { + // Return current wishlist info + if (req.method === 'GET') { + const body = { + customerToken, + includeProducts: req.query.products === '1', + } + return await handlers['getWishlist']({ req, res, config, body }) + } + + // Add an item to the wishlist + if (req.method === 'POST') { + const body = { ...req.body, customerToken } + return await handlers['addItem']({ req, res, config, body }) + } + + // Remove an item from the wishlist + if (req.method === 'DELETE') { + const body = { ...req.body, customerToken } + return await handlers['removeItem']({ req, res, config, body }) + } + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +export const handlers = { + getWishlist, + addItem, + removeItem, +} + +export default createApiHandler(wishlistApi, handlers, {}) diff --git a/framework/bigcommerce/auth/index.ts b/framework/bigcommerce/auth/index.ts new file mode 100644 index 00000000..36e757a8 --- /dev/null +++ b/framework/bigcommerce/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/framework/bigcommerce/auth/login.ts b/framework/bigcommerce/auth/login.ts new file mode 100644 index 00000000..3fef2987 --- /dev/null +++ b/framework/bigcommerce/auth/login.ts @@ -0,0 +1,73 @@ +import type { ServerResponse } from 'http' +import type { LoginMutation, LoginMutationVariables } from '../schema' +import type { RecursivePartial } from '../api/utils/types' +import concatHeader from '../api/utils/concat-cookie' +import { BigcommerceConfig, getConfig } from '../api' + +export const loginMutation = /* GraphQL */ ` + mutation login($email: String!, $password: String!) { + login(email: $email, password: $password) { + result + } + } +` + +export type LoginResult<T extends { result?: any } = { result?: string }> = T + +export type LoginVariables = LoginMutationVariables + +async function login(opts: { + variables: LoginVariables + config?: BigcommerceConfig + res: ServerResponse +}): Promise<LoginResult> + +async function login<T extends { result?: any }, V = any>(opts: { + query: string + variables: V + res: ServerResponse + config?: BigcommerceConfig +}): Promise<LoginResult<T>> + +async function login({ + query = loginMutation, + variables, + res: response, + config, +}: { + query?: string + variables: LoginVariables + res: ServerResponse + config?: BigcommerceConfig +}): Promise<LoginResult> { + config = getConfig(config) + + const { data, res } = await config.fetch<RecursivePartial<LoginMutation>>( + query, + { variables } + ) + // Bigcommerce returns a Set-Cookie header with the auth cookie + let cookie = res.headers.get('Set-Cookie') + + if (cookie && typeof cookie === 'string') { + // In development, don't set a secure cookie or the browser will ignore it + if (process.env.NODE_ENV !== 'production') { + cookie = cookie.replace('; Secure', '') + // SameSite=none can't be set unless the cookie is Secure + // bc seems to sometimes send back SameSite=None rather than none so make + // this case insensitive + cookie = cookie.replace(/; SameSite=none/gi, '; SameSite=lax') + } + + response.setHeader( + 'Set-Cookie', + concatHeader(response.getHeader('Set-Cookie'), cookie)! + ) + } + + return { + result: data.login?.result, + } +} + +export default login diff --git a/framework/bigcommerce/auth/use-login.tsx b/framework/bigcommerce/auth/use-login.tsx new file mode 100644 index 00000000..1be96a58 --- /dev/null +++ b/framework/bigcommerce/auth/use-login.tsx @@ -0,0 +1,40 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useLogin, { UseLogin } from '@commerce/auth/use-login' +import type { LoginBody } from '../api/customers/login' +import useCustomer from '../customer/use-customer' + +export default useLogin as UseLogin<typeof handler> + +export const handler: MutationHook<null, {}, LoginBody> = { + fetchOptions: { + url: '/api/bigcommerce/customers/login', + method: 'POST', + }, + async fetcher({ input: { email, password }, options, fetch }) { + if (!(email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to login', + }) + } + + return fetch({ + ...options, + body: { email, password }, + }) + }, + useHook: ({ fetch }) => () => { + const { revalidate } = useCustomer() + + return useCallback( + async function login(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/bigcommerce/auth/use-logout.tsx b/framework/bigcommerce/auth/use-logout.tsx new file mode 100644 index 00000000..71015a1c --- /dev/null +++ b/framework/bigcommerce/auth/use-logout.tsx @@ -0,0 +1,25 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import useLogout, { UseLogout } from '@commerce/auth/use-logout' +import useCustomer from '../customer/use-customer' + +export default useLogout as UseLogout<typeof handler> + +export const handler: MutationHook<null> = { + fetchOptions: { + url: '/api/bigcommerce/customers/logout', + method: 'GET', + }, + useHook: ({ fetch }) => () => { + const { mutate } = useCustomer() + + return useCallback( + async function logout() { + const data = await fetch() + await mutate(null, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/bigcommerce/auth/use-signup.tsx b/framework/bigcommerce/auth/use-signup.tsx new file mode 100644 index 00000000..28f7024e --- /dev/null +++ b/framework/bigcommerce/auth/use-signup.tsx @@ -0,0 +1,44 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useSignup, { UseSignup } from '@commerce/auth/use-signup' +import type { SignupBody } from '../api/customers/signup' +import useCustomer from '../customer/use-customer' + +export default useSignup as UseSignup<typeof handler> + +export const handler: MutationHook<null, {}, SignupBody, SignupBody> = { + fetchOptions: { + url: '/api/bigcommerce/customers/signup', + method: 'POST', + }, + async fetcher({ + input: { firstName, lastName, email, password }, + options, + fetch, + }) { + if (!(firstName && lastName && email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to signup', + }) + } + + return fetch({ + ...options, + body: { firstName, lastName, email, password }, + }) + }, + useHook: ({ fetch }) => () => { + const { revalidate } = useCustomer() + + return useCallback( + async function signup(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/bigcommerce/cart/index.ts b/framework/bigcommerce/cart/index.ts new file mode 100644 index 00000000..3b8ba990 --- /dev/null +++ b/framework/bigcommerce/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/framework/bigcommerce/cart/use-add-item.tsx b/framework/bigcommerce/cart/use-add-item.tsx new file mode 100644 index 00000000..d74c2356 --- /dev/null +++ b/framework/bigcommerce/cart/use-add-item.tsx @@ -0,0 +1,50 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' +import { normalizeCart } from '../lib/normalize' +import type { + Cart, + BigcommerceCart, + CartItemBody, + AddCartItemBody, +} from '../types' +import useCart from './use-cart' + +export default useAddItem as UseAddItem<typeof handler> + +export const handler: MutationHook<Cart, {}, CartItemBody> = { + fetchOptions: { + url: '/api/bigcommerce/cart', + method: 'POST', + }, + async fetcher({ input: item, options, fetch }) { + if ( + item.quantity && + (!Number.isInteger(item.quantity) || item.quantity! < 1) + ) { + throw new CommerceError({ + message: 'The item quantity has to be a valid integer greater than 0', + }) + } + + const data = await fetch<BigcommerceCart, AddCartItemBody>({ + ...options, + body: { item }, + }) + + return normalizeCart(data) + }, + useHook: ({ fetch }) => () => { + const { mutate } = useCart() + + return useCallback( + async function addItem(input) { + const data = await fetch({ input }) + await mutate(data, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/bigcommerce/cart/use-cart.tsx b/framework/bigcommerce/cart/use-cart.tsx new file mode 100644 index 00000000..2098e743 --- /dev/null +++ b/framework/bigcommerce/cart/use-cart.tsx @@ -0,0 +1,41 @@ +import { useMemo } from 'react' +import { SWRHook } from '@commerce/utils/types' +import useCart, { UseCart, FetchCartInput } from '@commerce/cart/use-cart' +import { normalizeCart } from '../lib/normalize' +import type { Cart } from '../types' + +export default useCart as UseCart<typeof handler> + +export const handler: SWRHook< + Cart | null, + {}, + FetchCartInput, + { isEmpty?: boolean } +> = { + fetchOptions: { + url: '/api/bigcommerce/cart', + method: 'GET', + }, + async fetcher({ input: { cartId }, options, fetch }) { + const data = cartId ? await fetch(options) : null + return data && normalizeCart(data) + }, + useHook: ({ useData }) => (input) => { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} diff --git a/framework/bigcommerce/cart/use-remove-item.tsx b/framework/bigcommerce/cart/use-remove-item.tsx new file mode 100644 index 00000000..186780d6 --- /dev/null +++ b/framework/bigcommerce/cart/use-remove-item.tsx @@ -0,0 +1,71 @@ +import { useCallback } from 'react' +import type { + MutationHookContext, + HookFetcherContext, +} from '@commerce/utils/types' +import { ValidationError } from '@commerce/utils/errors' +import useRemoveItem, { + RemoveItemInput as RemoveItemInputBase, + UseRemoveItem, +} from '@commerce/cart/use-remove-item' +import { normalizeCart } from '../lib/normalize' +import type { + RemoveCartItemBody, + Cart, + BigcommerceCart, + LineItem, +} from '../types' +import useCart from './use-cart' + +export type RemoveItemFn<T = any> = T extends LineItem + ? (input?: RemoveItemInput<T>) => Promise<Cart | null> + : (input: RemoveItemInput<T>) => Promise<Cart | null> + +export type RemoveItemInput<T = any> = T extends LineItem + ? Partial<RemoveItemInputBase> + : RemoveItemInputBase + +export default useRemoveItem as UseRemoveItem<typeof handler> + +export const handler = { + fetchOptions: { + url: '/api/bigcommerce/cart', + method: 'DELETE', + }, + async fetcher({ + input: { itemId }, + options, + fetch, + }: HookFetcherContext<RemoveCartItemBody>) { + const data = await fetch<BigcommerceCart>({ + ...options, + body: { itemId }, + }) + return normalizeCart(data) + }, + useHook: ({ + fetch, + }: MutationHookContext<Cart | null, RemoveCartItemBody>) => < + T extends LineItem | undefined = undefined + >( + ctx: { item?: T } = {} + ) => { + const { item } = ctx + const { mutate } = useCart() + const removeItem: RemoveItemFn<LineItem> = async (input) => { + const itemId = input?.id ?? item?.id + + if (!itemId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ input: { itemId } }) + await mutate(data, false) + return data + } + + return useCallback(removeItem as RemoveItemFn<T>, [fetch, mutate]) + }, +} diff --git a/framework/bigcommerce/cart/use-update-item.tsx b/framework/bigcommerce/cart/use-update-item.tsx new file mode 100644 index 00000000..f1840f80 --- /dev/null +++ b/framework/bigcommerce/cart/use-update-item.tsx @@ -0,0 +1,97 @@ +import { useCallback } from 'react' +import debounce from 'lodash.debounce' +import type { + MutationHookContext, + HookFetcherContext, +} from '@commerce/utils/types' +import { ValidationError } from '@commerce/utils/errors' +import useUpdateItem, { + UpdateItemInput as UpdateItemInputBase, + UseUpdateItem, +} from '@commerce/cart/use-update-item' +import { normalizeCart } from '../lib/normalize' +import type { + UpdateCartItemBody, + Cart, + BigcommerceCart, + LineItem, +} from '../types' +import { handler as removeItemHandler } from './use-remove-item' +import useCart from './use-cart' + +export type UpdateItemInput<T = any> = T extends LineItem + ? Partial<UpdateItemInputBase<LineItem>> + : UpdateItemInputBase<LineItem> + +export default useUpdateItem as UseUpdateItem<typeof handler> + +export const handler = { + fetchOptions: { + url: '/api/bigcommerce/cart', + method: 'PUT', + }, + async fetcher({ + input: { itemId, item }, + options, + fetch, + }: HookFetcherContext<UpdateCartItemBody>) { + if (Number.isInteger(item.quantity)) { + // Also allow the update hook to remove an item if the quantity is lower than 1 + if (item.quantity! < 1) { + return removeItemHandler.fetcher({ + options: removeItemHandler.fetchOptions, + input: { itemId }, + fetch, + }) + } + } else if (item.quantity) { + throw new ValidationError({ + message: 'The item quantity has to be a valid integer', + }) + } + + const data = await fetch<BigcommerceCart, UpdateCartItemBody>({ + ...options, + body: { itemId, item }, + }) + + return normalizeCart(data) + }, + useHook: ({ + fetch, + }: MutationHookContext<Cart | null, UpdateCartItemBody>) => < + T extends LineItem | undefined = undefined + >( + ctx: { + item?: T + wait?: number + } = {} + ) => { + const { item } = ctx + const { mutate } = useCart() as any + + return useCallback( + debounce(async (input: UpdateItemInput<T>) => { + const itemId = input.id ?? item?.id + const productId = input.productId ?? item?.productId + const variantId = input.productId ?? item?.variantId + + if (!itemId || !productId || !variantId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ + input: { + itemId, + item: { productId, variantId, quantity: input.quantity }, + }, + }) + await mutate(data, false) + return data + }, ctx.wait ?? 500), + [fetch, mutate] + ) + }, +} diff --git a/framework/bigcommerce/commerce.config.json b/framework/bigcommerce/commerce.config.json new file mode 100644 index 00000000..3a8738f4 --- /dev/null +++ b/framework/bigcommerce/commerce.config.json @@ -0,0 +1,6 @@ +{ + "provider": "bigcommerce", + "features": { + "wishlist": true + } +} diff --git a/framework/bigcommerce/common/get-all-pages.ts b/framework/bigcommerce/common/get-all-pages.ts new file mode 100644 index 00000000..dc5eb15a --- /dev/null +++ b/framework/bigcommerce/common/get-all-pages.ts @@ -0,0 +1,43 @@ +import type { RecursivePartial, RecursiveRequired } from '../api/utils/types' +import { BigcommerceConfig, getConfig } from '../api' +import { definitions } from '../api/definitions/store-content' + +export type Page = definitions['page_Full'] + +export type GetAllPagesResult< + T extends { pages: any[] } = { pages: Page[] } +> = T + +async function getAllPages(opts?: { + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetAllPagesResult> + +async function getAllPages<T extends { pages: any[] }>(opts: { + url: string + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetAllPagesResult<T>> + +async function getAllPages({ + config, + preview, +}: { + url?: string + config?: BigcommerceConfig + preview?: boolean +} = {}): Promise<GetAllPagesResult> { + config = getConfig(config) + // RecursivePartial forces the method to check for every prop in the data, which is + // required in case there's a custom `url` + const { data } = await config.storeApiFetch< + RecursivePartial<{ data: Page[] }> + >('/v3/content/pages') + const pages = (data as RecursiveRequired<typeof data>) ?? [] + + return { + pages: preview ? pages : pages.filter((p) => p.is_visible), + } +} + +export default getAllPages diff --git a/framework/bigcommerce/common/get-page.ts b/framework/bigcommerce/common/get-page.ts new file mode 100644 index 00000000..932032ef --- /dev/null +++ b/framework/bigcommerce/common/get-page.ts @@ -0,0 +1,53 @@ +import type { RecursivePartial, RecursiveRequired } from '../api/utils/types' +import { BigcommerceConfig, getConfig } from '../api' +import { definitions } from '../api/definitions/store-content' + +export type Page = definitions['page_Full'] + +export type GetPageResult<T extends { page?: any } = { page?: Page }> = T + +export type PageVariables = { + id: number +} + +async function getPage(opts: { + url?: string + variables: PageVariables + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetPageResult> + +async function getPage<T extends { page?: any }, V = any>(opts: { + url: string + variables: V + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetPageResult<T>> + +async function getPage({ + url, + variables, + config, + preview, +}: { + url?: string + variables: PageVariables + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetPageResult> { + config = getConfig(config) + // RecursivePartial forces the method to check for every prop in the data, which is + // required in case there's a custom `url` + const { data } = await config.storeApiFetch< + RecursivePartial<{ data: Page[] }> + >(url || `/v3/content/pages?id=${variables.id}&include=body`) + const firstPage = data?.[0] + const page = firstPage as RecursiveRequired<typeof firstPage> + + if (preview || page?.is_visible) { + return { page } + } + return {} +} + +export default getPage diff --git a/framework/bigcommerce/common/get-site-info.ts b/framework/bigcommerce/common/get-site-info.ts new file mode 100644 index 00000000..80cde8d8 --- /dev/null +++ b/framework/bigcommerce/common/get-site-info.ts @@ -0,0 +1,106 @@ +import type { GetSiteInfoQuery, GetSiteInfoQueryVariables } from '../schema' +import type { RecursivePartial, RecursiveRequired } from '../api/utils/types' +import filterEdges from '../api/utils/filter-edges' +import { BigcommerceConfig, getConfig } from '../api' +import { categoryTreeItemFragment } from '../api/fragments/category-tree' + +// Get 3 levels of categories +export const getSiteInfoQuery = /* GraphQL */ ` + query getSiteInfo { + site { + categoryTree { + ...categoryTreeItem + children { + ...categoryTreeItem + children { + ...categoryTreeItem + } + } + } + brands { + pageInfo { + startCursor + endCursor + } + edges { + cursor + node { + entityId + name + defaultImage { + urlOriginal + altText + } + pageTitle + metaDesc + metaKeywords + searchKeywords + path + } + } + } + } + } + ${categoryTreeItemFragment} +` + +export type CategoriesTree = NonNullable< + GetSiteInfoQuery['site']['categoryTree'] +> + +export type BrandEdge = NonNullable< + NonNullable<GetSiteInfoQuery['site']['brands']['edges']>[0] +> + +export type Brands = BrandEdge[] + +export type GetSiteInfoResult< + T extends { categories: any[]; brands: any[] } = { + categories: CategoriesTree + brands: Brands + } +> = T + +async function getSiteInfo(opts?: { + variables?: GetSiteInfoQueryVariables + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetSiteInfoResult> + +async function getSiteInfo< + T extends { categories: any[]; brands: any[] }, + V = any +>(opts: { + query: string + variables?: V + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetSiteInfoResult<T>> + +async function getSiteInfo({ + query = getSiteInfoQuery, + variables, + config, +}: { + query?: string + variables?: GetSiteInfoQueryVariables + config?: BigcommerceConfig + preview?: boolean +} = {}): Promise<GetSiteInfoResult> { + config = getConfig(config) + // RecursivePartial forces the method to check for every prop in the data, which is + // required in case there's a custom `query` + const { data } = await config.fetch<RecursivePartial<GetSiteInfoQuery>>( + query, + { variables } + ) + const categories = data.site?.categoryTree + const brands = data.site?.brands?.edges + + return { + categories: (categories as RecursiveRequired<typeof categories>) ?? [], + brands: filterEdges(brands as RecursiveRequired<typeof brands>), + } +} + +export default getSiteInfo diff --git a/framework/bigcommerce/customer/get-customer-id.ts b/framework/bigcommerce/customer/get-customer-id.ts new file mode 100644 index 00000000..65ce5a6a --- /dev/null +++ b/framework/bigcommerce/customer/get-customer-id.ts @@ -0,0 +1,34 @@ +import { GetCustomerIdQuery } from '../schema' +import { BigcommerceConfig, getConfig } from '../api' + +export const getCustomerIdQuery = /* GraphQL */ ` + query getCustomerId { + customer { + entityId + } + } +` + +async function getCustomerId({ + customerToken, + config, +}: { + customerToken: string + config?: BigcommerceConfig +}): Promise<number | undefined> { + config = getConfig(config) + + const { data } = await config.fetch<GetCustomerIdQuery>( + getCustomerIdQuery, + undefined, + { + headers: { + cookie: `${config.customerCookie}=${customerToken}`, + }, + } + ) + + return data?.customer?.entityId +} + +export default getCustomerId diff --git a/framework/bigcommerce/customer/get-customer-wishlist.ts b/framework/bigcommerce/customer/get-customer-wishlist.ts new file mode 100644 index 00000000..97e5654a --- /dev/null +++ b/framework/bigcommerce/customer/get-customer-wishlist.ts @@ -0,0 +1,88 @@ +import type { RecursivePartial, RecursiveRequired } from '../api/utils/types' +import { definitions } from '../api/definitions/wishlist' +import { BigcommerceConfig, getConfig } from '../api' +import getAllProducts, { ProductEdge } from '../product/get-all-products' + +export type Wishlist = Omit<definitions['wishlist_Full'], 'items'> & { + items?: WishlistItem[] +} + +export type WishlistItem = NonNullable< + definitions['wishlist_Full']['items'] +>[0] & { + product?: ProductEdge['node'] +} + +export type GetCustomerWishlistResult< + T extends { wishlist?: any } = { wishlist?: Wishlist } +> = T + +export type GetCustomerWishlistVariables = { + customerId: number +} + +async function getCustomerWishlist(opts: { + variables: GetCustomerWishlistVariables + config?: BigcommerceConfig + includeProducts?: boolean +}): Promise<GetCustomerWishlistResult> + +async function getCustomerWishlist< + T extends { wishlist?: any }, + V = any +>(opts: { + url: string + variables: V + config?: BigcommerceConfig + includeProducts?: boolean +}): Promise<GetCustomerWishlistResult<T>> + +async function getCustomerWishlist({ + config, + variables, + includeProducts, +}: { + url?: string + variables: GetCustomerWishlistVariables + config?: BigcommerceConfig + includeProducts?: boolean +}): Promise<GetCustomerWishlistResult> { + config = getConfig(config) + + const { data = [] } = await config.storeApiFetch< + RecursivePartial<{ data: Wishlist[] }> + >(`/v3/wishlists?customer_id=${variables.customerId}`) + const wishlist = data[0] + + if (includeProducts && wishlist?.items?.length) { + const entityIds = wishlist.items + ?.map((item) => item?.product_id) + .filter((id): id is number => !!id) + + if (entityIds?.length) { + const graphqlData = await getAllProducts({ + variables: { first: 100, entityIds }, + config, + }) + // Put the products in an object that we can use to get them by id + const productsById = graphqlData.products.reduce<{ + [k: number]: ProductEdge + }>((prods, p) => { + prods[Number(p.id)] = p as any + return prods + }, {}) + // Populate the wishlist items with the graphql products + wishlist.items.forEach((item) => { + const product = item && productsById[item.product_id!] + if (item && product) { + // @ts-ignore Fix this type when the wishlist type is properly defined + item.product = product + } + }) + } + } + + return { wishlist: wishlist as RecursiveRequired<typeof wishlist> } +} + +export default getCustomerWishlist diff --git a/framework/bigcommerce/customer/index.ts b/framework/bigcommerce/customer/index.ts new file mode 100644 index 00000000..6c903ecc --- /dev/null +++ b/framework/bigcommerce/customer/index.ts @@ -0,0 +1 @@ +export { default as useCustomer } from './use-customer' diff --git a/framework/bigcommerce/customer/use-customer.tsx b/framework/bigcommerce/customer/use-customer.tsx new file mode 100644 index 00000000..09300782 --- /dev/null +++ b/framework/bigcommerce/customer/use-customer.tsx @@ -0,0 +1,24 @@ +import { SWRHook } from '@commerce/utils/types' +import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' +import type { Customer, CustomerData } from '../api/customers' + +export default useCustomer as UseCustomer<typeof handler> + +export const handler: SWRHook<Customer | null> = { + fetchOptions: { + url: '/api/bigcommerce/customers', + method: 'GET', + }, + async fetcher({ options, fetch }) { + const data = await fetch<CustomerData | null>(options) + return data?.customer ?? null + }, + useHook: ({ useData }) => (input) => { + return useData({ + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions, + }, + }) + }, +} diff --git a/framework/bigcommerce/fetcher.ts b/framework/bigcommerce/fetcher.ts new file mode 100644 index 00000000..f8ca0c57 --- /dev/null +++ b/framework/bigcommerce/fetcher.ts @@ -0,0 +1,41 @@ +import { FetcherError } from '@commerce/utils/errors' +import type { Fetcher } from '@commerce/utils/types' + +async function getText(res: Response) { + try { + return (await res.text()) || res.statusText + } catch (error) { + return res.statusText + } +} + +async function getError(res: Response) { + if (res.headers.get('Content-Type')?.includes('application/json')) { + const data = await res.json() + return new FetcherError({ errors: data.errors, status: res.status }) + } + return new FetcherError({ message: await getText(res), status: res.status }) +} + +const fetcher: Fetcher = async ({ + url, + method = 'GET', + variables, + body: bodyObj, +}) => { + const hasBody = Boolean(variables || bodyObj) + const body = hasBody + ? JSON.stringify(variables ? { variables } : bodyObj) + : undefined + const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined + const res = await fetch(url!, { method, body, headers }) + + if (res.ok) { + const { data } = await res.json() + return data + } + + throw await getError(res) +} + +export default fetcher diff --git a/framework/bigcommerce/index.tsx b/framework/bigcommerce/index.tsx new file mode 100644 index 00000000..b35785ed --- /dev/null +++ b/framework/bigcommerce/index.tsx @@ -0,0 +1,35 @@ +import type { ReactNode } from 'react' +import { + CommerceConfig, + CommerceProvider as CoreCommerceProvider, + useCommerce as useCoreCommerce, +} from '@commerce' +import { bigcommerceProvider, BigcommerceProvider } from './provider' + +export { bigcommerceProvider } +export type { BigcommerceProvider } + +export const bigcommerceConfig: CommerceConfig = { + locale: 'en-us', + cartCookie: 'bc_cartId', +} + +export type BigcommerceConfig = Partial<CommerceConfig> + +export type BigcommerceProps = { + children?: ReactNode + locale: string +} & BigcommerceConfig + +export function CommerceProvider({ children, ...config }: BigcommerceProps) { + return ( + <CoreCommerceProvider + provider={bigcommerceProvider} + config={{ ...bigcommerceConfig, ...config }} + > + {children} + </CoreCommerceProvider> + ) +} + +export const useCommerce = () => useCoreCommerce<BigcommerceProvider>() diff --git a/framework/bigcommerce/lib/immutability.ts b/framework/bigcommerce/lib/immutability.ts new file mode 100644 index 00000000..488d3570 --- /dev/null +++ b/framework/bigcommerce/lib/immutability.ts @@ -0,0 +1,13 @@ +import update, { Context } from 'immutability-helper' + +const c = new Context() + +c.extend('$auto', function (value, object) { + return object ? c.update(object, value) : c.update({}, value) +}) + +c.extend('$autoArray', function (value, object) { + return object ? c.update(object, value) : c.update([], value) +}) + +export default c.update diff --git a/framework/bigcommerce/lib/normalize.ts b/framework/bigcommerce/lib/normalize.ts new file mode 100644 index 00000000..cc760609 --- /dev/null +++ b/framework/bigcommerce/lib/normalize.ts @@ -0,0 +1,113 @@ +import type { Product } from '@commerce/types' +import type { Cart, BigcommerceCart, LineItem } from '../types' +import update from './immutability' + +function normalizeProductOption(productOption: any) { + const { + node: { + entityId, + values: { edges }, + ...rest + }, + } = productOption + + return { + id: entityId, + values: edges?.map(({ node }: any) => node), + ...rest, + } +} + +export function normalizeProduct(productNode: any): Product { + const { + entityId: id, + productOptions, + prices, + path, + id: _, + options: _0, + } = productNode + + return update(productNode, { + id: { $set: String(id) }, + images: { + $apply: ({ edges }: any) => + edges?.map(({ node: { urlOriginal, altText, ...rest } }: any) => ({ + url: urlOriginal, + alt: altText, + ...rest, + })), + }, + variants: { + $apply: ({ edges }: any) => + edges?.map(({ node: { entityId, productOptions, ...rest } }: any) => ({ + id: entityId, + options: productOptions?.edges + ? productOptions.edges.map(normalizeProductOption) + : [], + ...rest, + })), + }, + options: { + $set: productOptions.edges + ? productOptions?.edges.map(normalizeProductOption) + : [], + }, + brand: { + $apply: (brand: any) => (brand?.entityId ? brand?.entityId : null), + }, + slug: { + $set: path?.replace(/^\/+|\/+$/g, ''), + }, + price: { + $set: { + value: prices?.price.value, + currencyCode: prices?.price.currencyCode, + }, + }, + $unset: ['entityId'], + }) +} + +export function normalizeCart(data: BigcommerceCart): Cart { + return { + id: data.id, + customerId: String(data.customer_id), + email: data.email, + createdAt: data.created_time, + currency: data.currency, + taxesIncluded: data.tax_included, + lineItems: data.line_items.physical_items.map(normalizeLineItem), + lineItemsSubtotalPrice: data.base_amount, + subtotalPrice: data.base_amount + data.discount_amount, + totalPrice: data.cart_amount, + discounts: data.discounts?.map((discount) => ({ + value: discount.discounted_amount, + })), + } +} + +function normalizeLineItem(item: any): LineItem { + return { + id: item.id, + variantId: String(item.variant_id), + productId: String(item.product_id), + name: item.name, + quantity: item.quantity, + variant: { + id: String(item.variant_id), + sku: item.sku, + name: item.name, + image: { + url: item.image_url, + }, + requiresShipping: item.is_require_shipping, + price: item.sale_price, + listPrice: item.list_price, + }, + path: item.url.split('/')[3], + discounts: item.discounts.map((discount: any) => ({ + value: discount.discounted_amount, + })), + } +} diff --git a/framework/bigcommerce/next.config.js b/framework/bigcommerce/next.config.js new file mode 100644 index 00000000..f33b1663 --- /dev/null +++ b/framework/bigcommerce/next.config.js @@ -0,0 +1,8 @@ +const commerce = require('./commerce.config.json') + +module.exports = { + commerce, + images: { + domains: ['cdn11.bigcommerce.com'], + }, +} diff --git a/framework/bigcommerce/product/get-all-product-paths.ts b/framework/bigcommerce/product/get-all-product-paths.ts new file mode 100644 index 00000000..c1b23b38 --- /dev/null +++ b/framework/bigcommerce/product/get-all-product-paths.ts @@ -0,0 +1,71 @@ +import type { + GetAllProductPathsQuery, + GetAllProductPathsQueryVariables, +} from '../schema' +import type { RecursivePartial, RecursiveRequired } from '../api/utils/types' +import filterEdges from '../api/utils/filter-edges' +import { BigcommerceConfig, getConfig } from '../api' + +export const getAllProductPathsQuery = /* GraphQL */ ` + query getAllProductPaths($first: Int = 100) { + site { + products(first: $first) { + edges { + node { + path + } + } + } + } + } +` + +export type ProductPath = NonNullable< + NonNullable<GetAllProductPathsQuery['site']['products']['edges']>[0] +> + +export type ProductPaths = ProductPath[] + +export type { GetAllProductPathsQueryVariables } + +export type GetAllProductPathsResult< + T extends { products: any[] } = { products: ProductPaths } +> = T + +async function getAllProductPaths(opts?: { + variables?: GetAllProductPathsQueryVariables + config?: BigcommerceConfig +}): Promise<GetAllProductPathsResult> + +async function getAllProductPaths< + T extends { products: any[] }, + V = any +>(opts: { + query: string + variables?: V + config?: BigcommerceConfig +}): Promise<GetAllProductPathsResult<T>> + +async function getAllProductPaths({ + query = getAllProductPathsQuery, + variables, + config, +}: { + query?: string + variables?: GetAllProductPathsQueryVariables + config?: BigcommerceConfig +} = {}): Promise<GetAllProductPathsResult> { + config = getConfig(config) + // RecursivePartial forces the method to check for every prop in the data, which is + // required in case there's a custom `query` + const { data } = await config.fetch< + RecursivePartial<GetAllProductPathsQuery> + >(query, { variables }) + const products = data.site?.products?.edges + + return { + products: filterEdges(products as RecursiveRequired<typeof products>), + } +} + +export default getAllProductPaths diff --git a/framework/bigcommerce/product/get-all-products.ts b/framework/bigcommerce/product/get-all-products.ts new file mode 100644 index 00000000..4c563bc6 --- /dev/null +++ b/framework/bigcommerce/product/get-all-products.ts @@ -0,0 +1,135 @@ +import type { + GetAllProductsQuery, + GetAllProductsQueryVariables, +} from '../schema' +import type { Product } from '@commerce/types' +import type { RecursivePartial, RecursiveRequired } from '../api/utils/types' +import filterEdges from '../api/utils/filter-edges' +import setProductLocaleMeta from '../api/utils/set-product-locale-meta' +import { productConnectionFragment } from '../api/fragments/product' +import { BigcommerceConfig, getConfig } from '../api' +import { normalizeProduct } from '../lib/normalize' + +export const getAllProductsQuery = /* GraphQL */ ` + query getAllProducts( + $hasLocale: Boolean = false + $locale: String = "null" + $entityIds: [Int!] + $first: Int = 10 + $products: Boolean = false + $featuredProducts: Boolean = false + $bestSellingProducts: Boolean = false + $newestProducts: Boolean = false + ) { + site { + products(first: $first, entityIds: $entityIds) @include(if: $products) { + ...productConnnection + } + featuredProducts(first: $first) @include(if: $featuredProducts) { + ...productConnnection + } + bestSellingProducts(first: $first) @include(if: $bestSellingProducts) { + ...productConnnection + } + newestProducts(first: $first) @include(if: $newestProducts) { + ...productConnnection + } + } + } + + ${productConnectionFragment} +` + +export type ProductEdge = NonNullable< + NonNullable<GetAllProductsQuery['site']['products']['edges']>[0] +> + +export type ProductNode = ProductEdge['node'] + +export type GetAllProductsResult< + T extends Record<keyof GetAllProductsResult, any[]> = { + products: ProductEdge[] + } +> = T + +const FIELDS = [ + 'products', + 'featuredProducts', + 'bestSellingProducts', + 'newestProducts', +] + +export type ProductTypes = + | 'products' + | 'featuredProducts' + | 'bestSellingProducts' + | 'newestProducts' + +export type ProductVariables = { field?: ProductTypes } & Omit< + GetAllProductsQueryVariables, + ProductTypes | 'hasLocale' +> + +async function getAllProducts(opts?: { + variables?: ProductVariables + config?: BigcommerceConfig + preview?: boolean +}): Promise<{ products: Product[] }> + +async function getAllProducts< + T extends Record<keyof GetAllProductsResult, any[]>, + V = any +>(opts: { + query: string + variables?: V + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetAllProductsResult<T>> + +async function getAllProducts({ + query = getAllProductsQuery, + variables: { field = 'products', ...vars } = {}, + config, +}: { + query?: string + variables?: ProductVariables + config?: BigcommerceConfig + preview?: boolean + // TODO: fix the product type here +} = {}): Promise<{ products: Product[] | any[] }> { + config = getConfig(config) + + const locale = vars.locale || config.locale + const variables: GetAllProductsQueryVariables = { + ...vars, + locale, + hasLocale: !!locale, + } + + if (!FIELDS.includes(field)) { + throw new Error( + `The field variable has to match one of ${FIELDS.join(', ')}` + ) + } + + variables[field] = true + + // RecursivePartial forces the method to check for every prop in the data, which is + // required in case there's a custom `query` + const { data } = await config.fetch<RecursivePartial<GetAllProductsQuery>>( + query, + { variables } + ) + const edges = data.site?.[field]?.edges + const products = filterEdges(edges as RecursiveRequired<typeof edges>) + + if (locale && config.applyLocale) { + products.forEach((product: RecursivePartial<ProductEdge>) => { + if (product.node) setProductLocaleMeta(product.node) + }) + } + + return { products: products.map(({ node }) => normalizeProduct(node as any)) } +} + +export default getAllProducts diff --git a/framework/bigcommerce/product/get-product.ts b/framework/bigcommerce/product/get-product.ts new file mode 100644 index 00000000..b52568b6 --- /dev/null +++ b/framework/bigcommerce/product/get-product.ts @@ -0,0 +1,121 @@ +import type { GetProductQuery, GetProductQueryVariables } from '../schema' +import setProductLocaleMeta from '../api/utils/set-product-locale-meta' +import { productInfoFragment } from '../api/fragments/product' +import { BigcommerceConfig, getConfig } from '../api' +import { normalizeProduct } from '../lib/normalize' +import type { Product } from '@commerce/types' + +export const getProductQuery = /* GraphQL */ ` + query getProduct( + $hasLocale: Boolean = false + $locale: String = "null" + $path: String! + ) { + site { + route(path: $path) { + node { + __typename + ... on Product { + ...productInfo + variants { + edges { + node { + entityId + defaultImage { + urlOriginal + altText + isDefault + } + prices { + ...productPrices + } + inventory { + aggregated { + availableToSell + warningLevel + } + isInStock + } + productOptions { + edges { + node { + __typename + entityId + displayName + ...multipleChoiceOption + } + } + } + } + } + } + } + } + } + } + } + + ${productInfoFragment} +` + +export type ProductNode = Extract< + GetProductQuery['site']['route']['node'], + { __typename: 'Product' } +> + +export type GetProductResult< + T extends { product?: any } = { product?: ProductNode } +> = T + +export type ProductVariables = { locale?: string } & ( + | { path: string; slug?: never } + | { path?: never; slug: string } +) + +async function getProduct(opts: { + variables: ProductVariables + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetProductResult> + +async function getProduct<T extends { product?: any }, V = any>(opts: { + query: string + variables: V + config?: BigcommerceConfig + preview?: boolean +}): Promise<GetProductResult<T>> + +async function getProduct({ + query = getProductQuery, + variables: { slug, ...vars }, + config, +}: { + query?: string + variables: ProductVariables + config?: BigcommerceConfig + preview?: boolean +}): Promise<Product | {} | any> { + config = getConfig(config) + + const locale = vars.locale || config.locale + const variables: GetProductQueryVariables = { + ...vars, + locale, + hasLocale: !!locale, + path: slug ? `/${slug}/` : vars.path!, + } + const { data } = await config.fetch<GetProductQuery>(query, { variables }) + const product = data.site?.route?.node + + if (product?.__typename === 'Product') { + if (locale && config.applyLocale) { + setProductLocaleMeta(product) + } + + return { product: normalizeProduct(product as any) } + } + + return {} +} + +export default getProduct diff --git a/framework/bigcommerce/product/index.ts b/framework/bigcommerce/product/index.ts new file mode 100644 index 00000000..b290c189 --- /dev/null +++ b/framework/bigcommerce/product/index.ts @@ -0,0 +1,4 @@ +export { default as usePrice } from './use-price' +export { default as useSearch } from './use-search' +export { default as getProduct } from './get-product' +export { default as getAllProducts } from './get-all-products' diff --git a/framework/bigcommerce/product/use-price.tsx b/framework/bigcommerce/product/use-price.tsx new file mode 100644 index 00000000..0174faf5 --- /dev/null +++ b/framework/bigcommerce/product/use-price.tsx @@ -0,0 +1,2 @@ +export * from '@commerce/product/use-price' +export { default } from '@commerce/product/use-price' diff --git a/framework/bigcommerce/product/use-search.tsx b/framework/bigcommerce/product/use-search.tsx new file mode 100644 index 00000000..0ee13503 --- /dev/null +++ b/framework/bigcommerce/product/use-search.tsx @@ -0,0 +1,53 @@ +import { SWRHook } from '@commerce/utils/types' +import useSearch, { UseSearch } from '@commerce/product/use-search' +import type { SearchProductsData } from '../api/catalog/products' + +export default useSearch as UseSearch<typeof handler> + +export type SearchProductsInput = { + search?: string + categoryId?: number + brandId?: number + sort?: string +} + +export const handler: SWRHook< + SearchProductsData, + SearchProductsInput, + SearchProductsInput +> = { + fetchOptions: { + url: '/api/bigcommerce/catalog/products', + method: 'GET', + }, + fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) { + // 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', search) + if (Number.isInteger(categoryId)) + url.searchParams.set('category', String(categoryId)) + if (Number.isInteger(brandId)) + url.searchParams.set('brand', String(brandId)) + if (sort) url.searchParams.set('sort', 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/framework/bigcommerce/provider.ts b/framework/bigcommerce/provider.ts new file mode 100644 index 00000000..19685543 --- /dev/null +++ b/framework/bigcommerce/provider.ts @@ -0,0 +1,34 @@ +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 useWishlist } from './wishlist/use-wishlist' +import { handler as useWishlistAddItem } from './wishlist/use-add-item' +import { handler as useWishlistRemoveItem } from './wishlist/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' + +import fetcher from './fetcher' + +export const bigcommerceProvider = { + locale: 'en-us', + cartCookie: 'bc_cartId', + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + wishlist: { + useWishlist, + useAddItem: useWishlistAddItem, + useRemoveItem: useWishlistRemoveItem, + }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, +} + +export type BigcommerceProvider = typeof bigcommerceProvider diff --git a/framework/bigcommerce/schema.d.ts b/framework/bigcommerce/schema.d.ts new file mode 100644 index 00000000..04824e26 --- /dev/null +++ b/framework/bigcommerce/schema.d.ts @@ -0,0 +1,2064 @@ +export type Maybe<T> = T | null +export type Exact<T extends { [key: string]: unknown }> = { + [K in keyof T]: T[K] +} +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string + String: string + Boolean: boolean + Int: number + Float: number + DateTime: any + /** The `BigDecimal` scalar type represents signed fractional values with arbitrary precision. */ + BigDecimal: any + /** The `Long` scalar type represents non-fractional signed whole numeric values. Long can represent values between -(2^63) and 2^63 - 1. */ + Long: any +} + +/** Login result */ +export type LoginResult = { + __typename?: 'LoginResult' + /** The result of a login */ + result: Scalars['String'] +} + +/** Logout result */ +export type LogoutResult = { + __typename?: 'LogoutResult' + /** The result of a logout */ + result: Scalars['String'] +} + +export type Mutation = { + __typename?: 'Mutation' + login: LoginResult + logout: LogoutResult +} + +export type MutationLoginArgs = { + email: Scalars['String'] + password: Scalars['String'] +} + +/** Aggregated */ +export type Aggregated = { + __typename?: 'Aggregated' + /** Number of available products in stock. This can be 'null' if inventory is not set orif the store's Inventory Settings disable displaying stock levels on the storefront. */ + availableToSell: Scalars['Long'] + /** Indicates a threshold low-stock level. This can be 'null' if the inventory warning level is not set or if the store's Inventory Settings disable displaying stock levels on the storefront. */ + warningLevel: Scalars['Int'] +} + +/** Aggregated Product Inventory */ +export type AggregatedInventory = { + __typename?: 'AggregatedInventory' + /** Number of available products in stock. This can be 'null' if inventory is not set orif the store's Inventory Settings disable displaying stock levels on the storefront. */ + availableToSell: Scalars['Int'] + /** Indicates a threshold low-stock level. This can be 'null' if the inventory warning level is not set or if the store's Inventory Settings disable displaying stock levels on the storefront. */ + warningLevel: Scalars['Int'] +} + +/** Brand */ +export type Brand = Node & { + __typename?: 'Brand' + /** The ID of an object */ + id: Scalars['ID'] + /** Id of the brand. */ + entityId: Scalars['Int'] + /** Name of the brand. */ + name: Scalars['String'] + /** Default image for brand. */ + defaultImage?: Maybe<Image> + /** Page title for the brand. */ + pageTitle: Scalars['String'] + /** Meta description for the brand. */ + metaDesc: Scalars['String'] + /** Meta keywords for the brand. */ + metaKeywords: Array<Scalars['String']> + /** Search keywords for the brand. */ + searchKeywords: Array<Scalars['String']> + /** Path for the brand page. */ + path: Scalars['String'] + products: ProductConnection + /** Metafield data related to a brand. */ + metafields: MetafieldConnection +} + +/** Brand */ +export type BrandProductsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Brand */ +export type BrandMetafieldsArgs = { + namespace: Scalars['String'] + keys?: Maybe<Array<Scalars['String']>> + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** A connection to a list of items. */ +export type BrandConnection = { + __typename?: 'BrandConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<BrandEdge>>> +} + +/** An edge in a connection. */ +export type BrandEdge = { + __typename?: 'BrandEdge' + /** The item at the end of the edge. */ + node: Brand + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** Breadcrumb */ +export type Breadcrumb = { + __typename?: 'Breadcrumb' + /** Category id. */ + entityId: Scalars['Int'] + /** Name of the category. */ + name: Scalars['String'] +} + +/** A connection to a list of items. */ +export type BreadcrumbConnection = { + __typename?: 'BreadcrumbConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<BreadcrumbEdge>>> +} + +/** An edge in a connection. */ +export type BreadcrumbEdge = { + __typename?: 'BreadcrumbEdge' + /** The item at the end of the edge. */ + node: Breadcrumb + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** Bulk pricing tier that sets a fixed price for the product or variant. */ +export type BulkPricingFixedPriceDiscount = BulkPricingTier & { + __typename?: 'BulkPricingFixedPriceDiscount' + /** This price will override the current product price. */ + price: Scalars['BigDecimal'] + /** Minimum item quantity that applies to this bulk pricing tier. */ + minimumQuantity: Scalars['Int'] + /** Maximum item quantity that applies to this bulk pricing tier - if not defined then the tier does not have an upper bound. */ + maximumQuantity?: Maybe<Scalars['Int']> +} + +/** Bulk pricing tier that reduces the price of the product or variant by a percentage. */ +export type BulkPricingPercentageDiscount = BulkPricingTier & { + __typename?: 'BulkPricingPercentageDiscount' + /** The percentage that will be removed from the product price. */ + percentOff: Scalars['BigDecimal'] + /** Minimum item quantity that applies to this bulk pricing tier. */ + minimumQuantity: Scalars['Int'] + /** Maximum item quantity that applies to this bulk pricing tier - if not defined then the tier does not have an upper bound. */ + maximumQuantity?: Maybe<Scalars['Int']> +} + +/** Bulk pricing tier that will subtract an amount from the price of the product or variant. */ +export type BulkPricingRelativePriceDiscount = BulkPricingTier & { + __typename?: 'BulkPricingRelativePriceDiscount' + /** The price of the product/variant will be reduced by this priceAdjustment. */ + priceAdjustment: Scalars['BigDecimal'] + /** Minimum item quantity that applies to this bulk pricing tier. */ + minimumQuantity: Scalars['Int'] + /** Maximum item quantity that applies to this bulk pricing tier - if not defined then the tier does not have an upper bound. */ + maximumQuantity?: Maybe<Scalars['Int']> +} + +/** A set of bulk pricing tiers that define price discounts which apply when purchasing specified quantities of a product or variant. */ +export type BulkPricingTier = { + /** Minimum item quantity that applies to this bulk pricing tier. */ + minimumQuantity: Scalars['Int'] + /** Maximum item quantity that applies to this bulk pricing tier - if not defined then the tier does not have an upper bound. */ + maximumQuantity?: Maybe<Scalars['Int']> +} + +/** Product Option */ +export type CatalogProductOption = { + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] +} + +/** Product Option Value */ +export type CatalogProductOptionValue = { + /** Unique ID for the option value. */ + entityId: Scalars['Int'] + /** Label for the option value. */ + label: Scalars['String'] + /** Indicates whether this value is the chosen default selected value. */ + isDefault: Scalars['Boolean'] +} + +/** Category */ +export type Category = Node & { + __typename?: 'Category' + /** The ID of an object */ + id: Scalars['ID'] + /** Unique ID for the category. */ + entityId: Scalars['Int'] + /** Category name. */ + name: Scalars['String'] + /** Category path. */ + path: Scalars['String'] + /** Default image for the category. */ + defaultImage?: Maybe<Image> + /** Category description. */ + description: Scalars['String'] + /** Category breadcrumbs. */ + breadcrumbs: BreadcrumbConnection + products: ProductConnection + /** Metafield data related to a category. */ + metafields: MetafieldConnection +} + +/** Category */ +export type CategoryBreadcrumbsArgs = { + depth: Scalars['Int'] + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Category */ +export type CategoryProductsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Category */ +export type CategoryMetafieldsArgs = { + namespace: Scalars['String'] + keys?: Maybe<Array<Scalars['String']>> + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** A connection to a list of items. */ +export type CategoryConnection = { + __typename?: 'CategoryConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<CategoryEdge>>> +} + +/** An edge in a connection. */ +export type CategoryEdge = { + __typename?: 'CategoryEdge' + /** The item at the end of the edge. */ + node: Category + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** An item in a tree of categories. */ +export type CategoryTreeItem = { + __typename?: 'CategoryTreeItem' + /** The id category. */ + entityId: Scalars['Int'] + /** The name of category. */ + name: Scalars['String'] + /** Path assigned to this category */ + path: Scalars['String'] + /** The description of this category. */ + description: Scalars['String'] + /** The number of products in this category. */ + productCount: Scalars['Int'] + /** Subcategories of this category */ + children: Array<CategoryTreeItem> +} + +/** A simple yes/no question represented by a checkbox. */ +export type CheckboxOption = CatalogProductOption & { + __typename?: 'CheckboxOption' + /** Indicates the default checked status. */ + checkedByDefault: Scalars['Boolean'] + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] +} + +/** Contact field */ +export type ContactField = { + __typename?: 'ContactField' + /** Store address line. */ + address: Scalars['String'] + /** Store country. */ + country: Scalars['String'] + /** Store address type. */ + addressType: Scalars['String'] + /** Store email. */ + email: Scalars['String'] + /** Store phone number. */ + phone: Scalars['String'] +} + +/** Custom field */ +export type CustomField = { + __typename?: 'CustomField' + /** Custom field id. */ + entityId: Scalars['Int'] + /** Name of the custom field. */ + name: Scalars['String'] + /** Value of the custom field. */ + value: Scalars['String'] +} + +/** A connection to a list of items. */ +export type CustomFieldConnection = { + __typename?: 'CustomFieldConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<CustomFieldEdge>>> +} + +/** An edge in a connection. */ +export type CustomFieldEdge = { + __typename?: 'CustomFieldEdge' + /** The item at the end of the edge. */ + node: CustomField + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** A customer that shops on a store */ +export type Customer = { + __typename?: 'Customer' + /** The ID of the customer. */ + entityId: Scalars['Int'] + /** The company name of the customer. */ + company: Scalars['String'] + /** The customer group id of the customer. */ + customerGroupId: Scalars['Int'] + /** The email address of the customer. */ + email: Scalars['String'] + /** The first name of the customer. */ + firstName: Scalars['String'] + /** The last name of the customer. */ + lastName: Scalars['String'] + /** The notes of the customer. */ + notes: Scalars['String'] + /** The phone number of the customer. */ + phone: Scalars['String'] + /** The tax exempt category of the customer. */ + taxExemptCategory: Scalars['String'] + /** Customer addresses count. */ + addressCount: Scalars['Int'] + /** Customer attributes count. */ + attributeCount: Scalars['Int'] + /** Customer store credit. */ + storeCredit: Array<Money> + /** Customer attributes. */ + attributes: CustomerAttributes +} + +/** A custom, store-specific attribute for a customer */ +export type CustomerAttribute = { + __typename?: 'CustomerAttribute' + /** The ID of the custom customer attribute */ + entityId: Scalars['Int'] + /** The value of the custom customer attribute */ + value?: Maybe<Scalars['String']> + /** The name of the custom customer attribute */ + name: Scalars['String'] +} + +/** Custom, store-specific customer attributes */ +export type CustomerAttributes = { + __typename?: 'CustomerAttributes' + attribute: CustomerAttribute +} + +/** Custom, store-specific customer attributes */ +export type CustomerAttributesAttributeArgs = { + entityId: Scalars['Int'] +} + +/** A calendar for allowing selection of a date. */ +export type DateFieldOption = CatalogProductOption & { + __typename?: 'DateFieldOption' + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] +} + +/** Date Time Extended */ +export type DateTimeExtended = { + __typename?: 'DateTimeExtended' + /** ISO-8601 formatted date in UTC */ + utc: Scalars['DateTime'] +} + +/** Display field */ +export type DisplayField = { + __typename?: 'DisplayField' + /** Short date format. */ + shortDateFormat: Scalars['String'] + /** Extended date format. */ + extendedDateFormat: Scalars['String'] +} + +/** A form allowing selection and uploading of a file from the user's local computer. */ +export type FileUploadFieldOption = CatalogProductOption & { + __typename?: 'FileUploadFieldOption' + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] +} + +/** Image */ +export type Image = { + __typename?: 'Image' + /** Absolute path to image using store CDN. */ + url: Scalars['String'] + /** Absolute path to original image using store CDN. */ + urlOriginal: Scalars['String'] + /** Text description of an image that can be used for SEO and/or accessibility purposes. */ + altText: Scalars['String'] + /** Indicates whether this is the primary image. */ + isDefault: Scalars['Boolean'] +} + +/** Image */ +export type ImageUrlArgs = { + width: Scalars['Int'] + height?: Maybe<Scalars['Int']> +} + +/** A connection to a list of items. */ +export type ImageConnection = { + __typename?: 'ImageConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<ImageEdge>>> +} + +/** An edge in a connection. */ +export type ImageEdge = { + __typename?: 'ImageEdge' + /** The item at the end of the edge. */ + node: Image + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** An inventory */ +export type Inventory = { + __typename?: 'Inventory' + /** Locations */ + locations: LocationConnection +} + +/** An inventory */ +export type InventoryLocationsArgs = { + entityIds?: Maybe<Array<Scalars['Int']>> + codes?: Maybe<Array<Scalars['String']>> + typeIds?: Maybe<Array<Scalars['String']>> + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Inventory By Locations */ +export type InventoryByLocations = { + __typename?: 'InventoryByLocations' + /** Location id. */ + locationEntityId: Scalars['Long'] + /** Number of available products in stock. */ + availableToSell: Scalars['Long'] + /** Indicates a threshold low-stock level. */ + warningLevel: Scalars['Int'] + /** Indicates whether this product is in stock. */ + isInStock: Scalars['Boolean'] +} + +/** A connection to a list of items. */ +export type LocationConnection = { + __typename?: 'LocationConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<LocationEdge>>> +} + +/** An edge in a connection. */ +export type LocationEdge = { + __typename?: 'LocationEdge' + /** The item at the end of the edge. */ + node: InventoryByLocations + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** Logo field */ +export type LogoField = { + __typename?: 'LogoField' + /** Logo title. */ + title: Scalars['String'] + /** Store logo image. */ + image: Image +} + +/** Measurement */ +export type Measurement = { + __typename?: 'Measurement' + /** Unformatted weight measurement value. */ + value: Scalars['Float'] + /** Unit of measurement. */ + unit: Scalars['String'] +} + +/** A connection to a list of items. */ +export type MetafieldConnection = { + __typename?: 'MetafieldConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<MetafieldEdge>>> +} + +/** An edge in a connection. */ +export type MetafieldEdge = { + __typename?: 'MetafieldEdge' + /** The item at the end of the edge. */ + node: Metafields + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** Key/Value pairs of data attached tied to a resource entity (product, brand, category, etc.) */ +export type Metafields = { + __typename?: 'Metafields' + /** The ID of an object */ + id: Scalars['ID'] + /** The ID of the metafield when referencing via our backend API. */ + entityId: Scalars['Int'] + /** A label for identifying a metafield data value. */ + key: Scalars['String'] + /** A metafield value. */ + value: Scalars['String'] +} + +/** A money object - includes currency code and a money amount */ +export type Money = { + __typename?: 'Money' + /** Currency code of the current money. */ + currencyCode: Scalars['String'] + /** The amount of money. */ + value: Scalars['BigDecimal'] +} + +/** A min and max pair of money objects */ +export type MoneyRange = { + __typename?: 'MoneyRange' + /** Minimum money object. */ + min: Money + /** Maximum money object. */ + max: Money +} + +/** A multi-line text input field, aka a text box. */ +export type MultiLineTextFieldOption = CatalogProductOption & { + __typename?: 'MultiLineTextFieldOption' + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] +} + +/** An option type that has a fixed list of values. */ +export type MultipleChoiceOption = CatalogProductOption & { + __typename?: 'MultipleChoiceOption' + /** The chosen display style for this multiple choice option. */ + displayStyle: Scalars['String'] + /** List of option values. */ + values: ProductOptionValueConnection + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] +} + +/** An option type that has a fixed list of values. */ +export type MultipleChoiceOptionValuesArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** A simple multiple choice value comprised of an id and a label. */ +export type MultipleChoiceOptionValue = CatalogProductOptionValue & { + __typename?: 'MultipleChoiceOptionValue' + /** Unique ID for the option value. */ + entityId: Scalars['Int'] + /** Label for the option value. */ + label: Scalars['String'] + /** Indicates whether this value is the chosen default selected value. */ + isDefault: Scalars['Boolean'] +} + +/** An object with an ID */ +export type Node = { + /** The id of the object. */ + id: Scalars['ID'] +} + +/** A single line text input field that only accepts numbers. */ +export type NumberFieldOption = CatalogProductOption & { + __typename?: 'NumberFieldOption' + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] +} + +/** A connection to a list of items. */ +export type OptionConnection = { + __typename?: 'OptionConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<OptionEdge>>> +} + +/** An edge in a connection. */ +export type OptionEdge = { + __typename?: 'OptionEdge' + /** The item at the end of the edge. */ + node: ProductOption + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** A connection to a list of items. */ +export type OptionValueConnection = { + __typename?: 'OptionValueConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<OptionValueEdge>>> +} + +/** An edge in a connection. */ +export type OptionValueEdge = { + __typename?: 'OptionValueEdge' + /** The item at the end of the edge. */ + node: ProductOptionValue + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +export type OptionValueId = { + optionEntityId: Scalars['Int'] + valueEntityId: Scalars['Int'] +} + +/** Information about pagination in a connection. */ +export type PageInfo = { + __typename?: 'PageInfo' + /** When paginating forwards, are there more items? */ + hasNextPage: Scalars['Boolean'] + /** When paginating backwards, are there more items? */ + hasPreviousPage: Scalars['Boolean'] + /** When paginating backwards, the cursor to continue. */ + startCursor?: Maybe<Scalars['String']> + /** When paginating forwards, the cursor to continue. */ + endCursor?: Maybe<Scalars['String']> +} + +/** The min and max range of prices that apply to this product. */ +export type PriceRanges = { + __typename?: 'PriceRanges' + /** Product price min/max range. */ + priceRange: MoneyRange + /** Product retail price min/max range. */ + retailPriceRange?: Maybe<MoneyRange> +} + +/** The various prices that can be set on a product. */ +export type Prices = { + __typename?: 'Prices' + /** Calculated price of the product. */ + price: Money + /** Sale price of the product. */ + salePrice?: Maybe<Money> + /** Original price of the product. */ + basePrice?: Maybe<Money> + /** Retail price of the product. */ + retailPrice?: Maybe<Money> + /** Minimum advertised price of the product. */ + mapPrice?: Maybe<Money> + /** Product price min/max range. */ + priceRange: MoneyRange + /** Product retail price min/max range. */ + retailPriceRange?: Maybe<MoneyRange> + /** The difference between the retail price (MSRP) and the current price, which can be presented to the shopper as their savings. */ + saved?: Maybe<Money> + /** List of bulk pricing tiers applicable to a product or variant. */ + bulkPricing: Array<BulkPricingTier> +} + +/** Product */ +export type Product = Node & { + __typename?: 'Product' + /** The ID of an object */ + id: Scalars['ID'] + /** Id of the product. */ + entityId: Scalars['Int'] + /** Default product variant when no options are selected. */ + sku: Scalars['String'] + /** Relative URL path to product page. */ + path: Scalars['String'] + /** Name of the product. */ + name: Scalars['String'] + /** Description of the product. */ + description: Scalars['String'] + /** Description of the product in plain text. */ + plainTextDescription: Scalars['String'] + /** Warranty information of the product. */ + warranty: Scalars['String'] + /** Minimum purchasable quantity for this product in a single order. */ + minPurchaseQuantity?: Maybe<Scalars['Int']> + /** Maximum purchasable quantity for this product in a single order. */ + maxPurchaseQuantity?: Maybe<Scalars['Int']> + /** Absolute URL path for adding a product to cart. */ + addToCartUrl: Scalars['String'] + /** Absolute URL path for adding a product to customer's wishlist. */ + addToWishlistUrl: Scalars['String'] + /** Prices object determined by supplied product ID, variant ID, and selected option IDs. */ + prices?: Maybe<Prices> + /** + * The minimum and maximum price of this product based on variant pricing and/or modifier price rules. + * @deprecated Use priceRanges inside prices node instead. + */ + priceRanges?: Maybe<PriceRanges> + /** Weight of the product. */ + weight?: Maybe<Measurement> + /** Height of the product. */ + height?: Maybe<Measurement> + /** Width of the product. */ + width?: Maybe<Measurement> + /** Depth of the product. */ + depth?: Maybe<Measurement> + /** Product options. */ + options: OptionConnection + /** Product options. */ + productOptions: ProductOptionConnection + /** Summary of the product reviews, includes the total number of reviews submitted and summation of the ratings on the reviews (ratings range from 0-5 per review). */ + reviewSummary: Reviews + /** Type of product, ex: physical, digital */ + type: Scalars['String'] + /** + * The availability state of the product. + * @deprecated Use status inside availabilityV2 instead. + */ + availability: Scalars['String'] + /** + * A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. + * @deprecated Use description inside availabilityV2 instead. + */ + availabilityDescription: Scalars['String'] + /** The availability state of the product. */ + availabilityV2: ProductAvailability + /** List of categories associated with the product. */ + categories: CategoryConnection + /** Brand associated with the product. */ + brand?: Maybe<Brand> + /** Variants associated with the product. */ + variants: VariantConnection + /** Custom fields of the product. */ + customFields: CustomFieldConnection + /** A list of the images for a product. */ + images: ImageConnection + /** Default image for a product. */ + defaultImage?: Maybe<Image> + /** Related products for this product. */ + relatedProducts: RelatedProductsConnection + /** Inventory information of the product. */ + inventory: ProductInventory + /** Metafield data related to a product. */ + metafields: MetafieldConnection + /** + * Product creation date + * @deprecated Alpha version. Do not use in production. + */ + createdAt: DateTimeExtended +} + +/** Product */ +export type ProductPlainTextDescriptionArgs = { + characterLimit?: Maybe<Scalars['Int']> +} + +/** Product */ +export type ProductPricesArgs = { + includeTax?: Maybe<Scalars['Boolean']> + currencyCode?: Maybe<CurrencyCode> +} + +/** Product */ +export type ProductPriceRangesArgs = { + includeTax?: Maybe<Scalars['Boolean']> +} + +/** Product */ +export type ProductOptionsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Product */ +export type ProductProductOptionsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Product */ +export type ProductCategoriesArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Product */ +export type ProductVariantsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> + entityIds?: Maybe<Array<Scalars['Int']>> + optionValueIds?: Maybe<Array<OptionValueId>> +} + +/** Product */ +export type ProductCustomFieldsArgs = { + names?: Maybe<Array<Scalars['String']>> + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Product */ +export type ProductImagesArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Product */ +export type ProductRelatedProductsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Product */ +export type ProductMetafieldsArgs = { + namespace: Scalars['String'] + keys?: Maybe<Array<Scalars['String']>> + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Product availability */ +export type ProductAvailability = { + /** The availability state of the product. */ + status: ProductAvailabilityStatus + /** A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. */ + description: Scalars['String'] +} + +/** Product availability status */ +export enum ProductAvailabilityStatus { + Available = 'Available', + Preorder = 'Preorder', + Unavailable = 'Unavailable', +} + +/** Available Product */ +export type ProductAvailable = ProductAvailability & { + __typename?: 'ProductAvailable' + /** The availability state of the product. */ + status: ProductAvailabilityStatus + /** A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. */ + description: Scalars['String'] +} + +/** A connection to a list of items. */ +export type ProductConnection = { + __typename?: 'ProductConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<ProductEdge>>> +} + +/** An edge in a connection. */ +export type ProductEdge = { + __typename?: 'ProductEdge' + /** The item at the end of the edge. */ + node: Product + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** Product Inventory Information */ +export type ProductInventory = { + __typename?: 'ProductInventory' + /** Indicates whether this product is in stock. */ + isInStock: Scalars['Boolean'] + /** Indicates whether this product's inventory is being tracked on variant level. If true, you may wish to check the variants node to understand the true inventory of each individual variant, rather than relying on this product-level aggregate to understand how many items may be added to cart. */ + hasVariantInventory: Scalars['Boolean'] + /** Aggregated product inventory information. This data may not be available if not set or if the store's Inventory Settings have disabled displaying stock levels on the storefront. */ + aggregated?: Maybe<AggregatedInventory> +} + +/** Product Option */ +export type ProductOption = { + __typename?: 'ProductOption' + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] + /** Option values. */ + values: OptionValueConnection +} + +/** Product Option */ +export type ProductOptionValuesArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** A connection to a list of items. */ +export type ProductOptionConnection = { + __typename?: 'ProductOptionConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<ProductOptionEdge>>> +} + +/** An edge in a connection. */ +export type ProductOptionEdge = { + __typename?: 'ProductOptionEdge' + /** The item at the end of the edge. */ + node: CatalogProductOption + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** Product Option Value */ +export type ProductOptionValue = { + __typename?: 'ProductOptionValue' + /** Unique ID for the option value. */ + entityId: Scalars['Int'] + /** Label for the option value. */ + label: Scalars['String'] +} + +/** A connection to a list of items. */ +export type ProductOptionValueConnection = { + __typename?: 'ProductOptionValueConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<ProductOptionValueEdge>>> +} + +/** An edge in a connection. */ +export type ProductOptionValueEdge = { + __typename?: 'ProductOptionValueEdge' + /** The item at the end of the edge. */ + node: CatalogProductOptionValue + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** A Product PickList Value - a product to be mapped to the base product if selected. */ +export type ProductPickListOptionValue = CatalogProductOptionValue & { + __typename?: 'ProductPickListOptionValue' + /** The ID of the product associated with this option value. */ + productId: Scalars['Int'] + /** Unique ID for the option value. */ + entityId: Scalars['Int'] + /** Label for the option value. */ + label: Scalars['String'] + /** Indicates whether this value is the chosen default selected value. */ + isDefault: Scalars['Boolean'] +} + +/** PreOrder Product */ +export type ProductPreOrder = ProductAvailability & { + __typename?: 'ProductPreOrder' + /** The message to be shown in the store when a product is put into the pre-order availability state, e.g. "Expected release date is %%DATE%%" */ + message?: Maybe<Scalars['String']> + /** Product release date */ + willBeReleasedAt?: Maybe<DateTimeExtended> + /** The availability state of the product. */ + status: ProductAvailabilityStatus + /** A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. */ + description: Scalars['String'] +} + +/** Unavailable Product */ +export type ProductUnavailable = ProductAvailability & { + __typename?: 'ProductUnavailable' + /** The message to be shown in the store when "Call for pricing" is enabled for this product, e.g. "Contact us at 555-5555" */ + message?: Maybe<Scalars['String']> + /** The availability state of the product. */ + status: ProductAvailabilityStatus + /** A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. */ + description: Scalars['String'] +} + +export type Query = { + __typename?: 'Query' + site: Site + /** The currently logged in customer. */ + customer?: Maybe<Customer> + /** Fetches an object given its ID */ + node?: Maybe<Node> + /** @deprecated Alpha version. Do not use in production. */ + inventory: Inventory +} + +export type QueryNodeArgs = { + id: Scalars['ID'] +} + +/** A connection to a list of items. */ +export type RelatedProductsConnection = { + __typename?: 'RelatedProductsConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<RelatedProductsEdge>>> +} + +/** An edge in a connection. */ +export type RelatedProductsEdge = { + __typename?: 'RelatedProductsEdge' + /** The item at the end of the edge. */ + node: Product + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** Review Rating Summary */ +export type Reviews = { + __typename?: 'Reviews' + /** Total number of reviews on product. */ + numberOfReviews: Scalars['Int'] + /** Summation of rating scores from each review. */ + summationOfRatings: Scalars['Int'] +} + +/** route */ +export type Route = { + __typename?: 'Route' + /** node */ + node?: Maybe<Node> +} + +/** Store settings information from the control panel. */ +export type Settings = { + __typename?: 'Settings' + /** The name of the store. */ + storeName: Scalars['String'] + /** The hash of the store. */ + storeHash: Scalars['String'] + /** The current store status. */ + status: StorefrontStatusType + /** Logo information for the store. */ + logo: LogoField + /** Contact information for the store. */ + contact?: Maybe<ContactField> + /** Store urls. */ + url: UrlField + /** Store display format information. */ + display: DisplayField + /** Channel ID. */ + channelId: Scalars['Long'] +} + +/** A site */ +export type Site = { + __typename?: 'Site' + categoryTree: Array<CategoryTreeItem> + /** Details of the brand. */ + brands: BrandConnection + /** Details of the products. */ + products: ProductConnection + /** Details of the newest products. */ + newestProducts: ProductConnection + /** Details of the best selling products. */ + bestSellingProducts: ProductConnection + /** Details of the featured products. */ + featuredProducts: ProductConnection + /** A single product object with variant pricing overlay capabilities. */ + product?: Maybe<Product> + /** Route for a node */ + route: Route + /** Store settings. */ + settings?: Maybe<Settings> +} + +/** A site */ +export type SiteBrandsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> + productEntityIds?: Maybe<Array<Scalars['Int']>> +} + +/** A site */ +export type SiteProductsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> + ids?: Maybe<Array<Scalars['ID']>> + entityIds?: Maybe<Array<Scalars['Int']>> +} + +/** A site */ +export type SiteNewestProductsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** A site */ +export type SiteBestSellingProductsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** A site */ +export type SiteFeaturedProductsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** A site */ +export type SiteProductArgs = { + id?: Maybe<Scalars['ID']> + entityId?: Maybe<Scalars['Int']> + variantEntityId?: Maybe<Scalars['Int']> + optionValueIds?: Maybe<Array<OptionValueId>> + sku?: Maybe<Scalars['String']> +} + +/** A site */ +export type SiteRouteArgs = { + path: Scalars['String'] +} + +/** Storefront Mode */ +export enum StorefrontStatusType { + Launched = 'LAUNCHED', + Maintenance = 'MAINTENANCE', + PreLaunch = 'PRE_LAUNCH', + Hibernation = 'HIBERNATION', +} + +/** A swatch option value - swatch values can be associated with a list of hexidecimal colors or an image. */ +export type SwatchOptionValue = CatalogProductOptionValue & { + __typename?: 'SwatchOptionValue' + /** List of up to 3 hex encoded colors to associate with a swatch value. */ + hexColors: Array<Scalars['String']> + /** Absolute path of a swatch texture image. */ + imageUrl?: Maybe<Scalars['String']> + /** Unique ID for the option value. */ + entityId: Scalars['Int'] + /** Label for the option value. */ + label: Scalars['String'] + /** Indicates whether this value is the chosen default selected value. */ + isDefault: Scalars['Boolean'] +} + +/** A swatch option value - swatch values can be associated with a list of hexidecimal colors or an image. */ +export type SwatchOptionValueImageUrlArgs = { + width: Scalars['Int'] + height?: Maybe<Scalars['Int']> +} + +/** A single line text input field. */ +export type TextFieldOption = CatalogProductOption & { + __typename?: 'TextFieldOption' + /** Unique ID for the option. */ + entityId: Scalars['Int'] + /** Display name for the option. */ + displayName: Scalars['String'] + /** One of the option values is required to be selected for the checkout. */ + isRequired: Scalars['Boolean'] +} + +/** Url field */ +export type UrlField = { + __typename?: 'UrlField' + /** Store url. */ + vanityUrl: Scalars['String'] + /** CDN url to fetch assets. */ + cdnUrl: Scalars['String'] +} + +/** Variant */ +export type Variant = Node & { + __typename?: 'Variant' + /** The ID of an object */ + id: Scalars['ID'] + /** Id of the variant. */ + entityId: Scalars['Int'] + /** Sku of the variant. */ + sku: Scalars['String'] + /** The variant's weight. If a weight was not explicitly specified on the variant, this will be the product's weight. */ + weight?: Maybe<Measurement> + /** The variant's height. If a height was not explicitly specified on the variant, this will be the product's height. */ + height?: Maybe<Measurement> + /** The variant's width. If a width was not explicitly specified on the variant, this will be the product's width. */ + width?: Maybe<Measurement> + /** The variant's depth. If a depth was not explicitly specified on the variant, this will be the product's depth. */ + depth?: Maybe<Measurement> + /** The options which define a variant. */ + options: OptionConnection + /** Product options that compose this variant. */ + productOptions: ProductOptionConnection + /** Default image for a variant. */ + defaultImage?: Maybe<Image> + /** Variant prices */ + prices?: Maybe<Prices> + /** Variant inventory */ + inventory?: Maybe<VariantInventory> + /** Metafield data related to a variant. */ + metafields: MetafieldConnection +} + +/** Variant */ +export type VariantOptionsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Variant */ +export type VariantProductOptionsArgs = { + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Variant */ +export type VariantPricesArgs = { + includeTax?: Maybe<Scalars['Boolean']> + currencyCode?: Maybe<CurrencyCode> +} + +/** Variant */ +export type VariantMetafieldsArgs = { + namespace: Scalars['String'] + keys?: Maybe<Array<Scalars['String']>> + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** A connection to a list of items. */ +export type VariantConnection = { + __typename?: 'VariantConnection' + /** Information to aid in pagination. */ + pageInfo: PageInfo + /** A list of edges. */ + edges?: Maybe<Array<Maybe<VariantEdge>>> +} + +/** An edge in a connection. */ +export type VariantEdge = { + __typename?: 'VariantEdge' + /** The item at the end of the edge. */ + node: Variant + /** A cursor for use in pagination. */ + cursor: Scalars['String'] +} + +/** Variant Inventory */ +export type VariantInventory = { + __typename?: 'VariantInventory' + /** Aggregated product variant inventory information. This data may not be available if not set or if the store's Inventory Settings have disabled displaying stock levels on the storefront. */ + aggregated?: Maybe<Aggregated> + /** Indicates whether this product is in stock. */ + isInStock: Scalars['Boolean'] + /** Inventory by locations. */ + byLocation?: Maybe<LocationConnection> +} + +/** Variant Inventory */ +export type VariantInventoryByLocationArgs = { + locationEntityIds?: Maybe<Array<Scalars['Int']>> + before?: Maybe<Scalars['String']> + after?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + last?: Maybe<Scalars['Int']> +} + +/** Please select a currency */ +export enum CurrencyCode { + Adp = 'ADP', + Aed = 'AED', + Afa = 'AFA', + Afn = 'AFN', + Alk = 'ALK', + All = 'ALL', + Amd = 'AMD', + Ang = 'ANG', + Aoa = 'AOA', + Aok = 'AOK', + Aon = 'AON', + Aor = 'AOR', + Ara = 'ARA', + Arl = 'ARL', + Arm = 'ARM', + Arp = 'ARP', + Ars = 'ARS', + Ats = 'ATS', + Aud = 'AUD', + Awg = 'AWG', + Azm = 'AZM', + Azn = 'AZN', + Bad = 'BAD', + Bam = 'BAM', + Ban = 'BAN', + Bbd = 'BBD', + Bdt = 'BDT', + Bec = 'BEC', + Bef = 'BEF', + Bel = 'BEL', + Bgl = 'BGL', + Bgm = 'BGM', + Bgn = 'BGN', + Bgo = 'BGO', + Bhd = 'BHD', + Bif = 'BIF', + Bmd = 'BMD', + Bnd = 'BND', + Bob = 'BOB', + Bol = 'BOL', + Bop = 'BOP', + Bov = 'BOV', + Brb = 'BRB', + Brc = 'BRC', + Bre = 'BRE', + Brl = 'BRL', + Brn = 'BRN', + Brr = 'BRR', + Brz = 'BRZ', + Bsd = 'BSD', + Btn = 'BTN', + Buk = 'BUK', + Bwp = 'BWP', + Byb = 'BYB', + Byr = 'BYR', + Bzd = 'BZD', + Cad = 'CAD', + Cdf = 'CDF', + Che = 'CHE', + Chf = 'CHF', + Chw = 'CHW', + Cle = 'CLE', + Clf = 'CLF', + Clp = 'CLP', + Cnx = 'CNX', + Cny = 'CNY', + Cop = 'COP', + Cou = 'COU', + Crc = 'CRC', + Csd = 'CSD', + Csk = 'CSK', + Cve = 'CVE', + Cyp = 'CYP', + Czk = 'CZK', + Ddm = 'DDM', + Dem = 'DEM', + Djf = 'DJF', + Dkk = 'DKK', + Dop = 'DOP', + Dzd = 'DZD', + Ecs = 'ECS', + Ecv = 'ECV', + Eek = 'EEK', + Egp = 'EGP', + Ern = 'ERN', + Esa = 'ESA', + Esb = 'ESB', + Esp = 'ESP', + Etb = 'ETB', + Eur = 'EUR', + Fim = 'FIM', + Fjd = 'FJD', + Fkp = 'FKP', + Frf = 'FRF', + Gbp = 'GBP', + Gek = 'GEK', + Gel = 'GEL', + Ghc = 'GHC', + Ghs = 'GHS', + Gip = 'GIP', + Gmd = 'GMD', + Gnf = 'GNF', + Gns = 'GNS', + Gqe = 'GQE', + Grd = 'GRD', + Gtq = 'GTQ', + Gwe = 'GWE', + Gwp = 'GWP', + Gyd = 'GYD', + Hkd = 'HKD', + Hnl = 'HNL', + Hrd = 'HRD', + Hrk = 'HRK', + Htg = 'HTG', + Huf = 'HUF', + Idr = 'IDR', + Iep = 'IEP', + Ilp = 'ILP', + Ilr = 'ILR', + Ils = 'ILS', + Inr = 'INR', + Iqd = 'IQD', + Isj = 'ISJ', + Isk = 'ISK', + Itl = 'ITL', + Jmd = 'JMD', + Jod = 'JOD', + Jpy = 'JPY', + Kes = 'KES', + Kgs = 'KGS', + Khr = 'KHR', + Kmf = 'KMF', + Krh = 'KRH', + Kro = 'KRO', + Krw = 'KRW', + Kwd = 'KWD', + Kyd = 'KYD', + Kzt = 'KZT', + Lak = 'LAK', + Lbp = 'LBP', + Lkr = 'LKR', + Lrd = 'LRD', + Lsl = 'LSL', + Ltl = 'LTL', + Ltt = 'LTT', + Luc = 'LUC', + Luf = 'LUF', + Lul = 'LUL', + Lvl = 'LVL', + Lvr = 'LVR', + Lyd = 'LYD', + Mad = 'MAD', + Maf = 'MAF', + Mcf = 'MCF', + Mdc = 'MDC', + Mdl = 'MDL', + Mga = 'MGA', + Mgf = 'MGF', + Mkd = 'MKD', + Mkn = 'MKN', + Mlf = 'MLF', + Mmk = 'MMK', + Mnt = 'MNT', + Mop = 'MOP', + Mro = 'MRO', + Mtl = 'MTL', + Mtp = 'MTP', + Mur = 'MUR', + Mvp = 'MVP', + Mvr = 'MVR', + Mwk = 'MWK', + Mxn = 'MXN', + Mxp = 'MXP', + Mxv = 'MXV', + Myr = 'MYR', + Mze = 'MZE', + Mzm = 'MZM', + Mzn = 'MZN', + Nad = 'NAD', + Ngn = 'NGN', + Nic = 'NIC', + Nio = 'NIO', + Nlg = 'NLG', + Nok = 'NOK', + Npr = 'NPR', + Nzd = 'NZD', + Omr = 'OMR', + Pab = 'PAB', + Pei = 'PEI', + Pen = 'PEN', + Pes = 'PES', + Pgk = 'PGK', + Php = 'PHP', + Pkr = 'PKR', + Pln = 'PLN', + Plz = 'PLZ', + Pte = 'PTE', + Pyg = 'PYG', + Qar = 'QAR', + Rhd = 'RHD', + Rol = 'ROL', + Ron = 'RON', + Rsd = 'RSD', + Rub = 'RUB', + Rur = 'RUR', + Rwf = 'RWF', + Sar = 'SAR', + Sbd = 'SBD', + Scr = 'SCR', + Sdd = 'SDD', + Sdg = 'SDG', + Sdp = 'SDP', + Sek = 'SEK', + Sgd = 'SGD', + Shp = 'SHP', + Sit = 'SIT', + Skk = 'SKK', + Sll = 'SLL', + Sos = 'SOS', + Srd = 'SRD', + Srg = 'SRG', + Ssp = 'SSP', + Std = 'STD', + Sur = 'SUR', + Svc = 'SVC', + Syp = 'SYP', + Szl = 'SZL', + Thb = 'THB', + Tjr = 'TJR', + Tjs = 'TJS', + Tmm = 'TMM', + Tmt = 'TMT', + Tnd = 'TND', + Top = 'TOP', + Tpe = 'TPE', + Trl = 'TRL', + Try = 'TRY', + Ttd = 'TTD', + Twd = 'TWD', + Tzs = 'TZS', + Uah = 'UAH', + Uak = 'UAK', + Ugs = 'UGS', + Ugx = 'UGX', + Usd = 'USD', + Usn = 'USN', + Uss = 'USS', + Uyi = 'UYI', + Uyp = 'UYP', + Uyu = 'UYU', + Uzs = 'UZS', + Veb = 'VEB', + Vef = 'VEF', + Vnd = 'VND', + Vnn = 'VNN', + Vuv = 'VUV', + Wst = 'WST', + Xaf = 'XAF', + Xcd = 'XCD', + Xeu = 'XEU', + Xfo = 'XFO', + Xfu = 'XFU', + Xof = 'XOF', + Xpf = 'XPF', + Xre = 'XRE', + Ydd = 'YDD', + Yer = 'YER', + Yud = 'YUD', + Yum = 'YUM', + Yun = 'YUN', + Yur = 'YUR', + Zal = 'ZAL', + Zar = 'ZAR', + Zmk = 'ZMK', + Zmw = 'ZMW', + Zrn = 'ZRN', + Zrz = 'ZRZ', + Zwd = 'ZWD', + Zwl = 'ZWL', + Zwr = 'ZWR', +} + +export type GetLoggedInCustomerQueryVariables = Exact<{ [key: string]: never }> + +export type GetLoggedInCustomerQuery = { __typename?: 'Query' } & { + customer?: Maybe< + { __typename?: 'Customer' } & Pick< + Customer, + | 'entityId' + | 'firstName' + | 'lastName' + | 'email' + | 'company' + | 'customerGroupId' + | 'notes' + | 'phone' + | 'addressCount' + | 'attributeCount' + > & { + storeCredit: Array< + { __typename?: 'Money' } & Pick<Money, 'value' | 'currencyCode'> + > + } + > +} + +export type CategoryTreeItemFragment = { + __typename?: 'CategoryTreeItem' +} & Pick< + CategoryTreeItem, + 'entityId' | 'name' | 'path' | 'description' | 'productCount' +> + +export type ProductPricesFragment = { __typename?: 'Prices' } & { + price: { __typename?: 'Money' } & Pick<Money, 'value' | 'currencyCode'> + salePrice?: Maybe< + { __typename?: 'Money' } & Pick<Money, 'value' | 'currencyCode'> + > + retailPrice?: Maybe< + { __typename?: 'Money' } & Pick<Money, 'value' | 'currencyCode'> + > +} + +export type SwatchOptionFragment = { __typename?: 'SwatchOptionValue' } & Pick< + SwatchOptionValue, + 'isDefault' | 'hexColors' +> + +export type MultipleChoiceOptionFragment = { + __typename?: 'MultipleChoiceOption' +} & { + values: { __typename?: 'ProductOptionValueConnection' } & { + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductOptionValueEdge' } & { + node: + | ({ __typename?: 'MultipleChoiceOptionValue' } & Pick< + MultipleChoiceOptionValue, + 'label' + >) + | ({ __typename?: 'ProductPickListOptionValue' } & Pick< + ProductPickListOptionValue, + 'label' + >) + | ({ __typename?: 'SwatchOptionValue' } & Pick< + SwatchOptionValue, + 'label' + > & + SwatchOptionFragment) + } + > + > + > + } +} + +export type ProductInfoFragment = { __typename?: 'Product' } & Pick< + Product, + 'entityId' | 'name' | 'path' | 'description' +> & { + brand?: Maybe<{ __typename?: 'Brand' } & Pick<Brand, 'entityId'>> + prices?: Maybe<{ __typename?: 'Prices' } & ProductPricesFragment> + images: { __typename?: 'ImageConnection' } & { + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ImageEdge' } & { + node: { __typename?: 'Image' } & Pick< + Image, + 'urlOriginal' | 'altText' | 'isDefault' + > + } + > + > + > + } + variants: { __typename?: 'VariantConnection' } & { + edges?: Maybe< + Array< + Maybe< + { __typename?: 'VariantEdge' } & { + node: { __typename?: 'Variant' } & Pick<Variant, 'entityId'> & { + defaultImage?: Maybe< + { __typename?: 'Image' } & Pick< + Image, + 'urlOriginal' | 'altText' | 'isDefault' + > + > + } + } + > + > + > + } + productOptions: { __typename?: 'ProductOptionConnection' } & { + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductOptionEdge' } & { + node: + | ({ __typename: 'CheckboxOption' } & Pick< + CheckboxOption, + 'entityId' | 'displayName' + >) + | ({ __typename: 'DateFieldOption' } & Pick< + DateFieldOption, + 'entityId' | 'displayName' + >) + | ({ __typename: 'FileUploadFieldOption' } & Pick< + FileUploadFieldOption, + 'entityId' | 'displayName' + >) + | ({ __typename: 'MultiLineTextFieldOption' } & Pick< + MultiLineTextFieldOption, + 'entityId' | 'displayName' + >) + | ({ __typename: 'MultipleChoiceOption' } & Pick< + MultipleChoiceOption, + 'entityId' | 'displayName' + > & + MultipleChoiceOptionFragment) + | ({ __typename: 'NumberFieldOption' } & Pick< + NumberFieldOption, + 'entityId' | 'displayName' + >) + | ({ __typename: 'TextFieldOption' } & Pick< + TextFieldOption, + 'entityId' | 'displayName' + >) + } + > + > + > + } + localeMeta: { __typename?: 'MetafieldConnection' } & { + edges?: Maybe< + Array< + Maybe< + { __typename?: 'MetafieldEdge' } & { + node: { __typename?: 'Metafields' } & Pick< + Metafields, + 'key' | 'value' + > + } + > + > + > + } + } + +export type ProductConnnectionFragment = { + __typename?: 'ProductConnection' +} & { + pageInfo: { __typename?: 'PageInfo' } & Pick< + PageInfo, + 'startCursor' | 'endCursor' + > + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductEdge' } & Pick<ProductEdge, 'cursor'> & { + node: { __typename?: 'Product' } & ProductInfoFragment + } + > + > + > +} + +export type GetAllProductPathsQueryVariables = Exact<{ + first?: Maybe<Scalars['Int']> +}> + +export type GetAllProductPathsQuery = { __typename?: 'Query' } & { + site: { __typename?: 'Site' } & { + products: { __typename?: 'ProductConnection' } & { + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductEdge' } & { + node: { __typename?: 'Product' } & Pick<Product, 'path'> + } + > + > + > + } + } +} + +export type GetAllProductsQueryVariables = Exact<{ + hasLocale?: Maybe<Scalars['Boolean']> + locale?: Maybe<Scalars['String']> + entityIds?: Maybe<Array<Scalars['Int']>> + first?: Maybe<Scalars['Int']> + products?: Maybe<Scalars['Boolean']> + featuredProducts?: Maybe<Scalars['Boolean']> + bestSellingProducts?: Maybe<Scalars['Boolean']> + newestProducts?: Maybe<Scalars['Boolean']> +}> + +export type GetAllProductsQuery = { __typename?: 'Query' } & { + site: { __typename?: 'Site' } & { + products: { __typename?: 'ProductConnection' } & ProductConnnectionFragment + featuredProducts: { + __typename?: 'ProductConnection' + } & ProductConnnectionFragment + bestSellingProducts: { + __typename?: 'ProductConnection' + } & ProductConnnectionFragment + newestProducts: { + __typename?: 'ProductConnection' + } & ProductConnnectionFragment + } +} + +export type GetCustomerIdQueryVariables = Exact<{ [key: string]: never }> + +export type GetCustomerIdQuery = { __typename?: 'Query' } & { + customer?: Maybe<{ __typename?: 'Customer' } & Pick<Customer, 'entityId'>> +} + +export type GetProductQueryVariables = Exact<{ + hasLocale?: Maybe<Scalars['Boolean']> + locale?: Maybe<Scalars['String']> + path: Scalars['String'] +}> + +export type GetProductQuery = { __typename?: 'Query' } & { + site: { __typename?: 'Site' } & { + route: { __typename?: 'Route' } & { + node?: Maybe< + | { __typename: 'Brand' } + | { __typename: 'Category' } + | ({ __typename: 'Product' } & { + variants: { __typename?: 'VariantConnection' } & { + edges?: Maybe< + Array< + Maybe< + { __typename?: 'VariantEdge' } & { + node: { __typename?: 'Variant' } & Pick< + Variant, + 'entityId' + > & { + defaultImage?: Maybe< + { __typename?: 'Image' } & Pick< + Image, + 'urlOriginal' | 'altText' | 'isDefault' + > + > + prices?: Maybe< + { __typename?: 'Prices' } & ProductPricesFragment + > + inventory?: Maybe< + { __typename?: 'VariantInventory' } & Pick< + VariantInventory, + 'isInStock' + > & { + aggregated?: Maybe< + { __typename?: 'Aggregated' } & Pick< + Aggregated, + 'availableToSell' | 'warningLevel' + > + > + } + > + productOptions: { + __typename?: 'ProductOptionConnection' + } & { + edges?: Maybe< + Array< + Maybe< + { __typename?: 'ProductOptionEdge' } & { + node: + | ({ + __typename: 'CheckboxOption' + } & Pick< + CheckboxOption, + 'entityId' | 'displayName' + >) + | ({ + __typename: 'DateFieldOption' + } & Pick< + DateFieldOption, + 'entityId' | 'displayName' + >) + | ({ + __typename: 'FileUploadFieldOption' + } & Pick< + FileUploadFieldOption, + 'entityId' | 'displayName' + >) + | ({ + __typename: 'MultiLineTextFieldOption' + } & Pick< + MultiLineTextFieldOption, + 'entityId' | 'displayName' + >) + | ({ + __typename: 'MultipleChoiceOption' + } & Pick< + MultipleChoiceOption, + 'entityId' | 'displayName' + > & + MultipleChoiceOptionFragment) + | ({ + __typename: 'NumberFieldOption' + } & Pick< + NumberFieldOption, + 'entityId' | 'displayName' + >) + | ({ + __typename: 'TextFieldOption' + } & Pick< + TextFieldOption, + 'entityId' | 'displayName' + >) + } + > + > + > + } + } + } + > + > + > + } + } & ProductInfoFragment) + | { __typename: 'Variant' } + > + } + } +} + +export type GetSiteInfoQueryVariables = Exact<{ [key: string]: never }> + +export type GetSiteInfoQuery = { __typename?: 'Query' } & { + site: { __typename?: 'Site' } & { + categoryTree: Array< + { __typename?: 'CategoryTreeItem' } & { + children: Array< + { __typename?: 'CategoryTreeItem' } & { + children: Array< + { __typename?: 'CategoryTreeItem' } & CategoryTreeItemFragment + > + } & CategoryTreeItemFragment + > + } & CategoryTreeItemFragment + > + brands: { __typename?: 'BrandConnection' } & { + pageInfo: { __typename?: 'PageInfo' } & Pick< + PageInfo, + 'startCursor' | 'endCursor' + > + edges?: Maybe< + Array< + Maybe< + { __typename?: 'BrandEdge' } & Pick<BrandEdge, 'cursor'> & { + node: { __typename?: 'Brand' } & Pick< + Brand, + | 'entityId' + | 'name' + | 'pageTitle' + | 'metaDesc' + | 'metaKeywords' + | 'searchKeywords' + | 'path' + > & { + defaultImage?: Maybe< + { __typename?: 'Image' } & Pick< + Image, + 'urlOriginal' | 'altText' + > + > + } + } + > + > + > + } + } +} + +export type LoginMutationVariables = Exact<{ + email: Scalars['String'] + password: Scalars['String'] +}> + +export type LoginMutation = { __typename?: 'Mutation' } & { + login: { __typename?: 'LoginResult' } & Pick<LoginResult, 'result'> +} diff --git a/framework/bigcommerce/schema.graphql b/framework/bigcommerce/schema.graphql new file mode 100644 index 00000000..79de347f --- /dev/null +++ b/framework/bigcommerce/schema.graphql @@ -0,0 +1,2422 @@ +""" +Login result +""" +type LoginResult { + """ + The result of a login + """ + result: String! +} + +""" +Logout result +""" +type LogoutResult { + """ + The result of a logout + """ + result: String! +} + +type Mutation { + login(email: String!, password: String!): LoginResult! + logout: LogoutResult! +} + +""" +Aggregated +""" +type Aggregated { + """ + Number of available products in stock. This can be 'null' if inventory is not set orif the store's Inventory Settings disable displaying stock levels on the storefront. + """ + availableToSell: Long! + + """ + Indicates a threshold low-stock level. This can be 'null' if the inventory warning level is not set or if the store's Inventory Settings disable displaying stock levels on the storefront. + """ + warningLevel: Int! +} + +""" +Aggregated Product Inventory +""" +type AggregatedInventory { + """ + Number of available products in stock. This can be 'null' if inventory is not set orif the store's Inventory Settings disable displaying stock levels on the storefront. + """ + availableToSell: Int! + + """ + Indicates a threshold low-stock level. This can be 'null' if the inventory warning level is not set or if the store's Inventory Settings disable displaying stock levels on the storefront. + """ + warningLevel: Int! +} + +""" +Brand +""" +type Brand implements Node { + """ + The ID of an object + """ + id: ID! + + """ + Id of the brand. + """ + entityId: Int! + + """ + Name of the brand. + """ + name: String! + + """ + Default image for brand. + """ + defaultImage: Image + + """ + Page title for the brand. + """ + pageTitle: String! + + """ + Meta description for the brand. + """ + metaDesc: String! + + """ + Meta keywords for the brand. + """ + metaKeywords: [String!]! + + """ + Search keywords for the brand. + """ + searchKeywords: [String!]! + + """ + Path for the brand page. + """ + path: String! + products( + before: String + after: String + first: Int + last: Int + ): ProductConnection! + + """ + Metafield data related to a brand. + """ + metafields( + namespace: String! + keys: [String!] = [] + before: String + after: String + first: Int + last: Int + ): MetafieldConnection! +} + +""" +A connection to a list of items. +""" +type BrandConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [BrandEdge] +} + +""" +An edge in a connection. +""" +type BrandEdge { + """ + The item at the end of the edge. + """ + node: Brand! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +Breadcrumb +""" +type Breadcrumb { + """ + Category id. + """ + entityId: Int! + + """ + Name of the category. + """ + name: String! +} + +""" +A connection to a list of items. +""" +type BreadcrumbConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [BreadcrumbEdge] +} + +""" +An edge in a connection. +""" +type BreadcrumbEdge { + """ + The item at the end of the edge. + """ + node: Breadcrumb! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +Bulk pricing tier that sets a fixed price for the product or variant. +""" +type BulkPricingFixedPriceDiscount implements BulkPricingTier { + """ + This price will override the current product price. + """ + price: BigDecimal! + + """ + Minimum item quantity that applies to this bulk pricing tier. + """ + minimumQuantity: Int! + + """ + Maximum item quantity that applies to this bulk pricing tier - if not defined then the tier does not have an upper bound. + """ + maximumQuantity: Int +} + +""" +Bulk pricing tier that reduces the price of the product or variant by a percentage. +""" +type BulkPricingPercentageDiscount implements BulkPricingTier { + """ + The percentage that will be removed from the product price. + """ + percentOff: BigDecimal! + + """ + Minimum item quantity that applies to this bulk pricing tier. + """ + minimumQuantity: Int! + + """ + Maximum item quantity that applies to this bulk pricing tier - if not defined then the tier does not have an upper bound. + """ + maximumQuantity: Int +} + +""" +Bulk pricing tier that will subtract an amount from the price of the product or variant. +""" +type BulkPricingRelativePriceDiscount implements BulkPricingTier { + """ + The price of the product/variant will be reduced by this priceAdjustment. + """ + priceAdjustment: BigDecimal! + + """ + Minimum item quantity that applies to this bulk pricing tier. + """ + minimumQuantity: Int! + + """ + Maximum item quantity that applies to this bulk pricing tier - if not defined then the tier does not have an upper bound. + """ + maximumQuantity: Int +} + +""" +A set of bulk pricing tiers that define price discounts which apply when purchasing specified quantities of a product or variant. +""" +interface BulkPricingTier { + """ + Minimum item quantity that applies to this bulk pricing tier. + """ + minimumQuantity: Int! + + """ + Maximum item quantity that applies to this bulk pricing tier - if not defined then the tier does not have an upper bound. + """ + maximumQuantity: Int +} + +""" +Product Option +""" +interface CatalogProductOption { + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! +} + +""" +Product Option Value +""" +interface CatalogProductOptionValue { + """ + Unique ID for the option value. + """ + entityId: Int! + + """ + Label for the option value. + """ + label: String! + + """ + Indicates whether this value is the chosen default selected value. + """ + isDefault: Boolean! +} + +""" +Category +""" +type Category implements Node { + """ + The ID of an object + """ + id: ID! + + """ + Unique ID for the category. + """ + entityId: Int! + + """ + Category name. + """ + name: String! + + """ + Category path. + """ + path: String! + + """ + Default image for the category. + """ + defaultImage: Image + + """ + Category description. + """ + description: String! + + """ + Category breadcrumbs. + """ + breadcrumbs( + depth: Int! + before: String + after: String + first: Int + last: Int + ): BreadcrumbConnection! + products( + before: String + after: String + first: Int + last: Int + ): ProductConnection! + + """ + Metafield data related to a category. + """ + metafields( + namespace: String! + keys: [String!] = [] + before: String + after: String + first: Int + last: Int + ): MetafieldConnection! +} + +""" +A connection to a list of items. +""" +type CategoryConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [CategoryEdge] +} + +""" +An edge in a connection. +""" +type CategoryEdge { + """ + The item at the end of the edge. + """ + node: Category! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +An item in a tree of categories. +""" +type CategoryTreeItem { + """ + The id category. + """ + entityId: Int! + + """ + The name of category. + """ + name: String! + + """ + Path assigned to this category + """ + path: String! + + """ + The description of this category. + """ + description: String! + + """ + The number of products in this category. + """ + productCount: Int! + + """ + Subcategories of this category + """ + children: [CategoryTreeItem!]! +} + +""" +A simple yes/no question represented by a checkbox. +""" +type CheckboxOption implements CatalogProductOption { + """ + Indicates the default checked status. + """ + checkedByDefault: Boolean! + + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! +} + +""" +Contact field +""" +type ContactField { + """ + Store address line. + """ + address: String! + + """ + Store country. + """ + country: String! + + """ + Store address type. + """ + addressType: String! + + """ + Store email. + """ + email: String! + + """ + Store phone number. + """ + phone: String! +} + +""" +Custom field +""" +type CustomField { + """ + Custom field id. + """ + entityId: Int! + + """ + Name of the custom field. + """ + name: String! + + """ + Value of the custom field. + """ + value: String! +} + +""" +A connection to a list of items. +""" +type CustomFieldConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [CustomFieldEdge] +} + +""" +An edge in a connection. +""" +type CustomFieldEdge { + """ + The item at the end of the edge. + """ + node: CustomField! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +A customer that shops on a store +""" +type Customer { + """ + The ID of the customer. + """ + entityId: Int! + + """ + The company name of the customer. + """ + company: String! + + """ + The customer group id of the customer. + """ + customerGroupId: Int! + + """ + The email address of the customer. + """ + email: String! + + """ + The first name of the customer. + """ + firstName: String! + + """ + The last name of the customer. + """ + lastName: String! + + """ + The notes of the customer. + """ + notes: String! + + """ + The phone number of the customer. + """ + phone: String! + + """ + The tax exempt category of the customer. + """ + taxExemptCategory: String! + + """ + Customer addresses count. + """ + addressCount: Int! + + """ + Customer attributes count. + """ + attributeCount: Int! + + """ + Customer store credit. + """ + storeCredit: [Money!]! + + """ + Customer attributes. + """ + attributes: CustomerAttributes! +} + +""" +A custom, store-specific attribute for a customer +""" +type CustomerAttribute { + """ + The ID of the custom customer attribute + """ + entityId: Int! + + """ + The value of the custom customer attribute + """ + value: String + + """ + The name of the custom customer attribute + """ + name: String! +} + +""" +Custom, store-specific customer attributes +""" +type CustomerAttributes { + attribute( + """ + The ID of the customer attribute + """ + entityId: Int! + ): CustomerAttribute! +} + +""" +A calendar for allowing selection of a date. +""" +type DateFieldOption implements CatalogProductOption { + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! +} + +scalar DateTime + +""" +Date Time Extended +""" +type DateTimeExtended { + """ + ISO-8601 formatted date in UTC + """ + utc: DateTime! +} + +""" +Display field +""" +type DisplayField { + """ + Short date format. + """ + shortDateFormat: String! + + """ + Extended date format. + """ + extendedDateFormat: String! +} + +""" +A form allowing selection and uploading of a file from the user's local computer. +""" +type FileUploadFieldOption implements CatalogProductOption { + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! +} + +""" +Image +""" +type Image { + """ + Absolute path to image using store CDN. + """ + url(width: Int!, height: Int): String! + + """ + Absolute path to original image using store CDN. + """ + urlOriginal: String! + + """ + Text description of an image that can be used for SEO and/or accessibility purposes. + """ + altText: String! + + """ + Indicates whether this is the primary image. + """ + isDefault: Boolean! +} + +""" +A connection to a list of items. +""" +type ImageConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [ImageEdge] +} + +""" +An edge in a connection. +""" +type ImageEdge { + """ + The item at the end of the edge. + """ + node: Image! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +An inventory +""" +type Inventory { + """ + Locations + """ + locations( + entityIds: [Int!] + codes: [String!] + typeIds: [String!] + before: String + after: String + first: Int + last: Int + ): LocationConnection! +} + +""" +Inventory By Locations +""" +type InventoryByLocations { + """ + Location id. + """ + locationEntityId: Long! + + """ + Number of available products in stock. + """ + availableToSell: Long! + + """ + Indicates a threshold low-stock level. + """ + warningLevel: Int! + + """ + Indicates whether this product is in stock. + """ + isInStock: Boolean! +} + +""" +A connection to a list of items. +""" +type LocationConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [LocationEdge] +} + +""" +An edge in a connection. +""" +type LocationEdge { + """ + The item at the end of the edge. + """ + node: InventoryByLocations! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +Logo field +""" +type LogoField { + """ + Logo title. + """ + title: String! + + """ + Store logo image. + """ + image: Image! +} + +""" +Measurement +""" +type Measurement { + """ + Unformatted weight measurement value. + """ + value: Float! + + """ + Unit of measurement. + """ + unit: String! +} + +""" +A connection to a list of items. +""" +type MetafieldConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [MetafieldEdge] +} + +""" +An edge in a connection. +""" +type MetafieldEdge { + """ + The item at the end of the edge. + """ + node: Metafields! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +Key/Value pairs of data attached tied to a resource entity (product, brand, category, etc.) +""" +type Metafields { + """ + The ID of an object + """ + id: ID! + + """ + The ID of the metafield when referencing via our backend API. + """ + entityId: Int! + + """ + A label for identifying a metafield data value. + """ + key: String! + + """ + A metafield value. + """ + value: String! +} + +""" +A money object - includes currency code and a money amount +""" +type Money { + """ + Currency code of the current money. + """ + currencyCode: String! + + """ + The amount of money. + """ + value: BigDecimal! +} + +""" +A min and max pair of money objects +""" +type MoneyRange { + """ + Minimum money object. + """ + min: Money! + + """ + Maximum money object. + """ + max: Money! +} + +""" +A multi-line text input field, aka a text box. +""" +type MultiLineTextFieldOption implements CatalogProductOption { + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! +} + +""" +An option type that has a fixed list of values. +""" +type MultipleChoiceOption implements CatalogProductOption { + """ + The chosen display style for this multiple choice option. + """ + displayStyle: String! + + """ + List of option values. + """ + values( + before: String + after: String + first: Int + last: Int + ): ProductOptionValueConnection! + + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! +} + +""" +A simple multiple choice value comprised of an id and a label. +""" +type MultipleChoiceOptionValue implements CatalogProductOptionValue { + """ + Unique ID for the option value. + """ + entityId: Int! + + """ + Label for the option value. + """ + label: String! + + """ + Indicates whether this value is the chosen default selected value. + """ + isDefault: Boolean! +} + +""" +An object with an ID +""" +interface Node { + """ + The id of the object. + """ + id: ID! +} + +""" +A single line text input field that only accepts numbers. +""" +type NumberFieldOption implements CatalogProductOption { + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! +} + +""" +A connection to a list of items. +""" +type OptionConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [OptionEdge] +} + +""" +An edge in a connection. +""" +type OptionEdge { + """ + The item at the end of the edge. + """ + node: ProductOption! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +A connection to a list of items. +""" +type OptionValueConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [OptionValueEdge] +} + +""" +An edge in a connection. +""" +type OptionValueEdge { + """ + The item at the end of the edge. + """ + node: ProductOptionValue! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +input OptionValueId { + optionEntityId: Int! + valueEntityId: Int! +} + +""" +Information about pagination in a connection. +""" +type PageInfo { + """ + When paginating forwards, are there more items? + """ + hasNextPage: Boolean! + + """ + When paginating backwards, are there more items? + """ + hasPreviousPage: Boolean! + + """ + When paginating backwards, the cursor to continue. + """ + startCursor: String + + """ + When paginating forwards, the cursor to continue. + """ + endCursor: String +} + +""" +The min and max range of prices that apply to this product. +""" +type PriceRanges { + """ + Product price min/max range. + """ + priceRange: MoneyRange! + + """ + Product retail price min/max range. + """ + retailPriceRange: MoneyRange +} + +""" +The various prices that can be set on a product. +""" +type Prices { + """ + Calculated price of the product. + """ + price: Money! + + """ + Sale price of the product. + """ + salePrice: Money + + """ + Original price of the product. + """ + basePrice: Money + + """ + Retail price of the product. + """ + retailPrice: Money + + """ + Minimum advertised price of the product. + """ + mapPrice: Money + + """ + Product price min/max range. + """ + priceRange: MoneyRange! + + """ + Product retail price min/max range. + """ + retailPriceRange: MoneyRange + + """ + The difference between the retail price (MSRP) and the current price, which can be presented to the shopper as their savings. + """ + saved: Money + + """ + List of bulk pricing tiers applicable to a product or variant. + """ + bulkPricing: [BulkPricingTier!]! +} + +""" +Product +""" +type Product implements Node { + """ + The ID of an object + """ + id: ID! + + """ + Id of the product. + """ + entityId: Int! + + """ + Default product variant when no options are selected. + """ + sku: String! + + """ + Relative URL path to product page. + """ + path: String! + + """ + Name of the product. + """ + name: String! + + """ + Description of the product. + """ + description: String! + + """ + Description of the product in plain text. + """ + plainTextDescription(characterLimit: Int = 120): String! + + """ + Warranty information of the product. + """ + warranty: String! + + """ + Minimum purchasable quantity for this product in a single order. + """ + minPurchaseQuantity: Int + + """ + Maximum purchasable quantity for this product in a single order. + """ + maxPurchaseQuantity: Int + + """ + Absolute URL path for adding a product to cart. + """ + addToCartUrl: String! + + """ + Absolute URL path for adding a product to customer's wishlist. + """ + addToWishlistUrl: String! + + """ + Prices object determined by supplied product ID, variant ID, and selected option IDs. + """ + prices(includeTax: Boolean = false, currencyCode: currencyCode): Prices + + """ + The minimum and maximum price of this product based on variant pricing and/or modifier price rules. + """ + priceRanges(includeTax: Boolean = false): PriceRanges + @deprecated(reason: "Use priceRanges inside prices node instead.") + + """ + Weight of the product. + """ + weight: Measurement + + """ + Height of the product. + """ + height: Measurement + + """ + Width of the product. + """ + width: Measurement + + """ + Depth of the product. + """ + depth: Measurement + + """ + Product options. + """ + options( + before: String + after: String + first: Int + last: Int + ): OptionConnection! + + """ + Product options. + """ + productOptions( + before: String + after: String + first: Int + last: Int + ): ProductOptionConnection! + + """ + Summary of the product reviews, includes the total number of reviews submitted and summation of the ratings on the reviews (ratings range from 0-5 per review). + """ + reviewSummary: Reviews! + + """ + Type of product, ex: physical, digital + """ + type: String! + + """ + The availability state of the product. + """ + availability: String! + @deprecated(reason: "Use status inside availabilityV2 instead.") + + """ + A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. + """ + availabilityDescription: String! + @deprecated(reason: "Use description inside availabilityV2 instead.") + + """ + The availability state of the product. + """ + availabilityV2: ProductAvailability! + + """ + List of categories associated with the product. + """ + categories( + before: String + after: String + first: Int + last: Int + ): CategoryConnection! + + """ + Brand associated with the product. + """ + brand: Brand + + """ + Variants associated with the product. + """ + variants( + before: String + after: String + first: Int + last: Int + entityIds: [Int!] = [] + optionValueIds: [OptionValueId!] = [] + ): VariantConnection! + + """ + Custom fields of the product. + """ + customFields( + names: [String!] = [] + before: String + after: String + first: Int + last: Int + ): CustomFieldConnection! + + """ + A list of the images for a product. + """ + images(before: String, after: String, first: Int, last: Int): ImageConnection! + + """ + Default image for a product. + """ + defaultImage: Image + + """ + Related products for this product. + """ + relatedProducts( + before: String + after: String + first: Int + last: Int + ): RelatedProductsConnection! + + """ + Inventory information of the product. + """ + inventory: ProductInventory! + + """ + Metafield data related to a product. + """ + metafields( + namespace: String! + keys: [String!] = [] + before: String + after: String + first: Int + last: Int + ): MetafieldConnection! + + """ + Product creation date + """ + createdAt: DateTimeExtended! + @deprecated(reason: "Alpha version. Do not use in production.") +} + +""" +Product availability +""" +interface ProductAvailability { + """ + The availability state of the product. + """ + status: ProductAvailabilityStatus! + + """ + A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. + """ + description: String! +} + +""" +Product availability status +""" +enum ProductAvailabilityStatus { + Available + Preorder + Unavailable +} + +""" +Available Product +""" +type ProductAvailable implements ProductAvailability { + """ + The availability state of the product. + """ + status: ProductAvailabilityStatus! + + """ + A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. + """ + description: String! +} + +""" +A connection to a list of items. +""" +type ProductConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [ProductEdge] +} + +""" +An edge in a connection. +""" +type ProductEdge { + """ + The item at the end of the edge. + """ + node: Product! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +Product Inventory Information +""" +type ProductInventory { + """ + Indicates whether this product is in stock. + """ + isInStock: Boolean! + + """ + Indicates whether this product's inventory is being tracked on variant level. If true, you may wish to check the variants node to understand the true inventory of each individual variant, rather than relying on this product-level aggregate to understand how many items may be added to cart. + """ + hasVariantInventory: Boolean! + + """ + Aggregated product inventory information. This data may not be available if not set or if the store's Inventory Settings have disabled displaying stock levels on the storefront. + """ + aggregated: AggregatedInventory +} + +""" +Product Option +""" +type ProductOption { + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! + + """ + Option values. + """ + values( + before: String + after: String + first: Int + last: Int + ): OptionValueConnection! +} + +""" +A connection to a list of items. +""" +type ProductOptionConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [ProductOptionEdge] +} + +""" +An edge in a connection. +""" +type ProductOptionEdge { + """ + The item at the end of the edge. + """ + node: CatalogProductOption! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +Product Option Value +""" +type ProductOptionValue { + """ + Unique ID for the option value. + """ + entityId: Int! + + """ + Label for the option value. + """ + label: String! +} + +""" +A connection to a list of items. +""" +type ProductOptionValueConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [ProductOptionValueEdge] +} + +""" +An edge in a connection. +""" +type ProductOptionValueEdge { + """ + The item at the end of the edge. + """ + node: CatalogProductOptionValue! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +A Product PickList Value - a product to be mapped to the base product if selected. +""" +type ProductPickListOptionValue implements CatalogProductOptionValue { + """ + The ID of the product associated with this option value. + """ + productId: Int! + + """ + Unique ID for the option value. + """ + entityId: Int! + + """ + Label for the option value. + """ + label: String! + + """ + Indicates whether this value is the chosen default selected value. + """ + isDefault: Boolean! +} + +""" +PreOrder Product +""" +type ProductPreOrder implements ProductAvailability { + """ + The message to be shown in the store when a product is put into the pre-order availability state, e.g. "Expected release date is %%DATE%%" + """ + message: String + + """ + Product release date + """ + willBeReleasedAt: DateTimeExtended + + """ + The availability state of the product. + """ + status: ProductAvailabilityStatus! + + """ + A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. + """ + description: String! +} + +""" +Unavailable Product +""" +type ProductUnavailable implements ProductAvailability { + """ + The message to be shown in the store when "Call for pricing" is enabled for this product, e.g. "Contact us at 555-5555" + """ + message: String + + """ + The availability state of the product. + """ + status: ProductAvailabilityStatus! + + """ + A few words telling the customer how long it will normally take to ship this product, such as 'Usually ships in 24 hours'. + """ + description: String! +} + +type Query { + site: Site! + + """ + The currently logged in customer. + """ + customer: Customer + + """ + Fetches an object given its ID + """ + node( + """ + The ID of an object + """ + id: ID! + ): Node + inventory: Inventory! + @deprecated(reason: "Alpha version. Do not use in production.") +} + +""" +A connection to a list of items. +""" +type RelatedProductsConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [RelatedProductsEdge] +} + +""" +An edge in a connection. +""" +type RelatedProductsEdge { + """ + The item at the end of the edge. + """ + node: Product! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +Review Rating Summary +""" +type Reviews { + """ + Total number of reviews on product. + """ + numberOfReviews: Int! + + """ + Summation of rating scores from each review. + """ + summationOfRatings: Int! +} + +""" +route +""" +type Route { + """ + node + """ + node: Node +} + +""" +Store settings information from the control panel. +""" +type Settings { + """ + The name of the store. + """ + storeName: String! + + """ + The hash of the store. + """ + storeHash: String! + + """ + The current store status. + """ + status: StorefrontStatusType! + + """ + Logo information for the store. + """ + logo: LogoField! + + """ + Contact information for the store. + """ + contact: ContactField + + """ + Store urls. + """ + url: UrlField! + + """ + Store display format information. + """ + display: DisplayField! + + """ + Channel ID. + """ + channelId: Long! +} + +""" +A site +""" +type Site { + categoryTree: [CategoryTreeItem!]! + + """ + Details of the brand. + """ + brands( + before: String + after: String + first: Int + last: Int + productEntityIds: [Int!] = [] + ): BrandConnection! + + """ + Details of the products. + """ + products( + before: String + after: String + first: Int + last: Int + ids: [ID!] = [] + entityIds: [Int!] = [] + ): ProductConnection! + + """ + Details of the newest products. + """ + newestProducts( + before: String + after: String + first: Int + last: Int + ): ProductConnection! + + """ + Details of the best selling products. + """ + bestSellingProducts( + before: String + after: String + first: Int + last: Int + ): ProductConnection! + + """ + Details of the featured products. + """ + featuredProducts( + before: String + after: String + first: Int + last: Int + ): ProductConnection! + + """ + A single product object with variant pricing overlay capabilities. + """ + product( + id: ID + entityId: Int + variantEntityId: Int + optionValueIds: [OptionValueId!] = [] + sku: String + ): Product + + """ + Route for a node + """ + route(path: String!): Route! + + """ + Store settings. + """ + settings: Settings +} + +""" +Storefront Mode +""" +enum StorefrontStatusType { + LAUNCHED + MAINTENANCE + PRE_LAUNCH + HIBERNATION +} + +""" +A swatch option value - swatch values can be associated with a list of hexidecimal colors or an image. +""" +type SwatchOptionValue implements CatalogProductOptionValue { + """ + List of up to 3 hex encoded colors to associate with a swatch value. + """ + hexColors: [String!]! + + """ + Absolute path of a swatch texture image. + """ + imageUrl(width: Int!, height: Int): String + + """ + Unique ID for the option value. + """ + entityId: Int! + + """ + Label for the option value. + """ + label: String! + + """ + Indicates whether this value is the chosen default selected value. + """ + isDefault: Boolean! +} + +""" +A single line text input field. +""" +type TextFieldOption implements CatalogProductOption { + """ + Unique ID for the option. + """ + entityId: Int! + + """ + Display name for the option. + """ + displayName: String! + + """ + One of the option values is required to be selected for the checkout. + """ + isRequired: Boolean! +} + +""" +Url field +""" +type UrlField { + """ + Store url. + """ + vanityUrl: String! + + """ + CDN url to fetch assets. + """ + cdnUrl: String! +} + +""" +Variant +""" +type Variant implements Node { + """ + The ID of an object + """ + id: ID! + + """ + Id of the variant. + """ + entityId: Int! + + """ + Sku of the variant. + """ + sku: String! + + """ + The variant's weight. If a weight was not explicitly specified on the variant, this will be the product's weight. + """ + weight: Measurement + + """ + The variant's height. If a height was not explicitly specified on the variant, this will be the product's height. + """ + height: Measurement + + """ + The variant's width. If a width was not explicitly specified on the variant, this will be the product's width. + """ + width: Measurement + + """ + The variant's depth. If a depth was not explicitly specified on the variant, this will be the product's depth. + """ + depth: Measurement + + """ + The options which define a variant. + """ + options( + before: String + after: String + first: Int + last: Int + ): OptionConnection! + + """ + Product options that compose this variant. + """ + productOptions( + before: String + after: String + first: Int + last: Int + ): ProductOptionConnection! + + """ + Default image for a variant. + """ + defaultImage: Image + + """ + Variant prices + """ + prices(includeTax: Boolean = false, currencyCode: currencyCode): Prices + + """ + Variant inventory + """ + inventory: VariantInventory + + """ + Metafield data related to a variant. + """ + metafields( + namespace: String! + keys: [String!] = [] + before: String + after: String + first: Int + last: Int + ): MetafieldConnection! +} + +""" +A connection to a list of items. +""" +type VariantConnection { + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + + """ + A list of edges. + """ + edges: [VariantEdge] +} + +""" +An edge in a connection. +""" +type VariantEdge { + """ + The item at the end of the edge. + """ + node: Variant! + + """ + A cursor for use in pagination. + """ + cursor: String! +} + +""" +Variant Inventory +""" +type VariantInventory { + """ + Aggregated product variant inventory information. This data may not be available if not set or if the store's Inventory Settings have disabled displaying stock levels on the storefront. + """ + aggregated: Aggregated + + """ + Indicates whether this product is in stock. + """ + isInStock: Boolean! + + """ + Inventory by locations. + """ + byLocation( + locationEntityIds: [Int!] = [] + before: String + after: String + first: Int + last: Int + ): LocationConnection +} + +""" +Please select a currency +""" +enum currencyCode { + ADP + AED + AFA + AFN + ALK + ALL + AMD + ANG + AOA + AOK + AON + AOR + ARA + ARL + ARM + ARP + ARS + ATS + AUD + AWG + AZM + AZN + BAD + BAM + BAN + BBD + BDT + BEC + BEF + BEL + BGL + BGM + BGN + BGO + BHD + BIF + BMD + BND + BOB + BOL + BOP + BOV + BRB + BRC + BRE + BRL + BRN + BRR + BRZ + BSD + BTN + BUK + BWP + BYB + BYR + BZD + CAD + CDF + CHE + CHF + CHW + CLE + CLF + CLP + CNX + CNY + COP + COU + CRC + CSD + CSK + CVE + CYP + CZK + DDM + DEM + DJF + DKK + DOP + DZD + ECS + ECV + EEK + EGP + ERN + ESA + ESB + ESP + ETB + EUR + FIM + FJD + FKP + FRF + GBP + GEK + GEL + GHC + GHS + GIP + GMD + GNF + GNS + GQE + GRD + GTQ + GWE + GWP + GYD + HKD + HNL + HRD + HRK + HTG + HUF + IDR + IEP + ILP + ILR + ILS + INR + IQD + ISJ + ISK + ITL + JMD + JOD + JPY + KES + KGS + KHR + KMF + KRH + KRO + KRW + KWD + KYD + KZT + LAK + LBP + LKR + LRD + LSL + LTL + LTT + LUC + LUF + LUL + LVL + LVR + LYD + MAD + MAF + MCF + MDC + MDL + MGA + MGF + MKD + MKN + MLF + MMK + MNT + MOP + MRO + MTL + MTP + MUR + MVP + MVR + MWK + MXN + MXP + MXV + MYR + MZE + MZM + MZN + NAD + NGN + NIC + NIO + NLG + NOK + NPR + NZD + OMR + PAB + PEI + PEN + PES + PGK + PHP + PKR + PLN + PLZ + PTE + PYG + QAR + RHD + ROL + RON + RSD + RUB + RUR + RWF + SAR + SBD + SCR + SDD + SDG + SDP + SEK + SGD + SHP + SIT + SKK + SLL + SOS + SRD + SRG + SSP + STD + SUR + SVC + SYP + SZL + THB + TJR + TJS + TMM + TMT + TND + TOP + TPE + TRL + TRY + TTD + TWD + TZS + UAH + UAK + UGS + UGX + USD + USN + USS + UYI + UYP + UYU + UZS + VEB + VEF + VND + VNN + VUV + WST + XAF + XCD + XEU + XFO + XFU + XOF + XPF + XRE + YDD + YER + YUD + YUM + YUN + YUR + ZAL + ZAR + ZMK + ZMW + ZRN + ZRZ + ZWD + ZWL + ZWR +} + +""" +The `BigDecimal` scalar type represents signed fractional values with arbitrary precision. +""" +scalar BigDecimal + +""" +The `Long` scalar type represents non-fractional signed whole numeric values. Long can represent values between -(2^63) and 2^63 - 1. +""" +scalar Long diff --git a/framework/bigcommerce/scripts/generate-definitions.js b/framework/bigcommerce/scripts/generate-definitions.js new file mode 100644 index 00000000..a2b830d3 --- /dev/null +++ b/framework/bigcommerce/scripts/generate-definitions.js @@ -0,0 +1,49 @@ +/** + * Generates definitions for REST API endpoints that are being + * used by ../api using https://github.com/drwpow/swagger-to-ts + */ +const { readFileSync, promises } = require('fs') +const path = require('path') +const fetch = require('node-fetch') +const swaggerToTS = require('@manifoldco/swagger-to-ts').default + +async function getSchema(filename) { + const url = `https://next-api.stoplight.io/projects/8433/files/${filename}` + const res = await fetch(url) + + if (!res.ok) { + throw new Error(`Request failed with ${res.status}: ${res.statusText}`) + } + + return res.json() +} + +const schemas = Object.entries({ + '../api/definitions/catalog.ts': + 'BigCommerce_Catalog_API.oas2.yml?ref=version%2F20.930', + '../api/definitions/store-content.ts': + 'BigCommerce_Store_Content_API.oas2.yml?ref=version%2F20.930', + '../api/definitions/wishlist.ts': + 'BigCommerce_Wishlist_API.oas2.yml?ref=version%2F20.930', + // swagger-to-ts is not working for the schema of the cart API + // '../api/definitions/cart.ts': + // 'BigCommerce_Server_to_Server_Cart_API.oas2.yml', +}) + +async function writeDefinitions() { + const ops = schemas.map(async ([dest, filename]) => { + const destination = path.join(__dirname, dest) + const schema = await getSchema(filename) + const definition = swaggerToTS(schema.content, { + prettierConfig: 'package.json', + }) + + await promises.writeFile(destination, definition) + + console.log(`✔️ Added definitions for: ${dest}`) + }) + + await Promise.all(ops) +} + +writeDefinitions() diff --git a/framework/bigcommerce/types.ts b/framework/bigcommerce/types.ts new file mode 100644 index 00000000..beeab022 --- /dev/null +++ b/framework/bigcommerce/types.ts @@ -0,0 +1,58 @@ +import * as Core from '@commerce/types' + +// TODO: this type should match: +// https://developer.bigcommerce.com/api-reference/cart-checkout/server-server-cart-api/cart/getacart#responses +export type BigcommerceCart = { + id: string + parent_id?: string + customer_id: number + email: string + currency: { code: string } + tax_included: boolean + base_amount: number + discount_amount: number + cart_amount: number + line_items: { + custom_items: any[] + digital_items: any[] + gift_certificates: any[] + physical_items: any[] + } + created_time: string + discounts?: { id: number; discounted_amount: number }[] + // TODO: add missing fields +} + +export type Cart = Core.Cart & { + lineItems: LineItem[] +} + +export type LineItem = Core.LineItem + +/** + * Cart mutations + */ + +export type OptionSelections = { + option_id: number + option_value: number | string +} + +export type CartItemBody = Core.CartItemBody & { + productId: string // The product id is always required for BC + optionSelections?: OptionSelections +} + +export type GetCartHandlerBody = Core.GetCartHandlerBody + +export type AddCartItemBody = Core.AddCartItemBody<CartItemBody> + +export type AddCartItemHandlerBody = Core.AddCartItemHandlerBody<CartItemBody> + +export type UpdateCartItemBody = Core.UpdateCartItemBody<CartItemBody> + +export type UpdateCartItemHandlerBody = Core.UpdateCartItemHandlerBody<CartItemBody> + +export type RemoveCartItemBody = Core.RemoveCartItemBody + +export type RemoveCartItemHandlerBody = Core.RemoveCartItemHandlerBody diff --git a/framework/bigcommerce/wishlist/index.ts b/framework/bigcommerce/wishlist/index.ts new file mode 100644 index 00000000..241af3c7 --- /dev/null +++ b/framework/bigcommerce/wishlist/index.ts @@ -0,0 +1,3 @@ +export { default as useAddItem } from './use-add-item' +export { default as useWishlist } from './use-wishlist' +export { default as useRemoveItem } from './use-remove-item' diff --git a/framework/bigcommerce/wishlist/use-add-item.tsx b/framework/bigcommerce/wishlist/use-add-item.tsx new file mode 100644 index 00000000..402e7da8 --- /dev/null +++ b/framework/bigcommerce/wishlist/use-add-item.tsx @@ -0,0 +1,37 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useAddItem, { UseAddItem } from '@commerce/wishlist/use-add-item' +import type { ItemBody, AddItemBody } from '../api/wishlist' +import useCustomer from '../customer/use-customer' +import useWishlist from './use-wishlist' + +export default useAddItem as UseAddItem<typeof handler> + +export const handler: MutationHook<any, {}, ItemBody, AddItemBody> = { + fetchOptions: { + url: '/api/bigcommerce/wishlist', + method: 'POST', + }, + useHook: ({ fetch }) => () => { + const { data: customer } = useCustomer() + const { revalidate } = useWishlist() + + return useCallback( + async function addItem(item) { + if (!customer) { + // A signed customer is required in order to have a wishlist + throw new CommerceError({ + message: 'Signed customer not found', + }) + } + + // TODO: add validations before doing the fetch + const data = await fetch({ input: { item } }) + await revalidate() + return data + }, + [fetch, revalidate, customer] + ) + }, +} diff --git a/framework/bigcommerce/wishlist/use-remove-item.tsx b/framework/bigcommerce/wishlist/use-remove-item.tsx new file mode 100644 index 00000000..622f321d --- /dev/null +++ b/framework/bigcommerce/wishlist/use-remove-item.tsx @@ -0,0 +1,44 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useRemoveItem, { + RemoveItemInput, + UseRemoveItem, +} from '@commerce/wishlist/use-remove-item' +import type { RemoveItemBody, Wishlist } from '../api/wishlist' +import useCustomer from '../customer/use-customer' +import useWishlist, { UseWishlistInput } from './use-wishlist' + +export default useRemoveItem as UseRemoveItem<typeof handler> + +export const handler: MutationHook< + Wishlist | null, + { wishlist?: UseWishlistInput }, + RemoveItemInput, + RemoveItemBody +> = { + fetchOptions: { + url: '/api/bigcommerce/wishlist', + method: 'DELETE', + }, + useHook: ({ fetch }) => ({ wishlist } = {}) => { + const { data: customer } = useCustomer() + const { revalidate } = useWishlist(wishlist) + + return useCallback( + async function removeItem(input) { + if (!customer) { + // A signed customer is required in order to have a wishlist + throw new CommerceError({ + message: 'Signed customer not found', + }) + } + + const data = await fetch({ input: { itemId: String(input.id) } }) + await revalidate() + return data + }, + [fetch, revalidate, customer] + ) + }, +} diff --git a/framework/bigcommerce/wishlist/use-wishlist.tsx b/framework/bigcommerce/wishlist/use-wishlist.tsx new file mode 100644 index 00000000..4850d1cd --- /dev/null +++ b/framework/bigcommerce/wishlist/use-wishlist.tsx @@ -0,0 +1,60 @@ +import { useMemo } from 'react' +import { SWRHook } from '@commerce/utils/types' +import useWishlist, { UseWishlist } from '@commerce/wishlist/use-wishlist' +import type { Wishlist } from '../api/wishlist' +import useCustomer from '../customer/use-customer' + +export type UseWishlistInput = { includeProducts?: boolean } + +export default useWishlist as UseWishlist<typeof handler> + +export const handler: SWRHook< + Wishlist | null, + UseWishlistInput, + { customerId?: number } & UseWishlistInput, + { isEmpty?: boolean } +> = { + fetchOptions: { + url: '/api/bigcommerce/wishlist', + method: 'GET', + }, + async fetcher({ input: { customerId, includeProducts }, options, fetch }) { + if (!customerId) return null + + // Use a dummy base as we only care about the relative path + const url = new URL(options.url!, 'http://a') + + if (includeProducts) url.searchParams.set('products', '1') + + return fetch({ + url: url.pathname + url.search, + method: options.method, + }) + }, + useHook: ({ useData }) => (input) => { + const { data: customer } = useCustomer() + const response = useData({ + input: [ + ['customerId', customer?.entityId], + ['includeProducts', input?.includeProducts], + ], + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions, + }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.items?.length || 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} diff --git a/framework/commerce/README.md b/framework/commerce/README.md new file mode 100644 index 00000000..ecdebb8c --- /dev/null +++ b/framework/commerce/README.md @@ -0,0 +1,334 @@ +# Commerce Framework + +- [Commerce Framework](#commerce-framework) + - [Commerce Hooks](#commerce-hooks) + - [CommerceProvider](#commerceprovider) + - [Authentication Hooks](#authentication-hooks) + - [useSignup](#usesignup) + - [useLogin](#uselogin) + - [useLogout](#uselogout) + - [Customer Hooks](#customer-hooks) + - [useCustomer](#usecustomer) + - [Product Hooks](#product-hooks) + - [usePrice](#useprice) + - [useSearch](#usesearch) + - [Cart Hooks](#cart-hooks) + - [useCart](#usecart) + - [useAddItem](#useadditem) + - [useUpdateItem](#useupdateitem) + - [useRemoveItem](#useremoveitem) + - [Wishlist Hooks](#wishlist-hooks) + - [Commerce API](#commerce-api) + - [More](#more) + +The commerce framework ships multiple hooks and a Node.js API, both using an underlying headless e-commerce platform, which we call commerce providers. + +The core features are: + +- Code splitted hooks for data fetching using [SWR](https://swr.vercel.app/), and to handle common user actions +- A Node.js API for initial data population, static generation of content and for creating the API endpoints that connect to the hooks, if required. + +> 👩‍🔬 If you would like to contribute a new provider, check the docs for [Adding a new Commerce Provider](./new-provider.md). + +> 🚧 The core commerce framework is under active development, new features and updates will be continuously added over time. Breaking changes are expected while we finish the API. + +## Commerce Hooks + +A commerce hook is a [React hook](https://reactjs.org/docs/hooks-intro.html) that's connected to a commerce provider. They focus on user actions and data fetching of data that wasn't statically generated. + +Data fetching hooks use [SWR](https://swr.vercel.app/) underneath and you're welcome to use any of its [return values](https://swr.vercel.app/docs/options#return-values) and [options](https://swr.vercel.app/docs/options#options). For example, using the `useCustomer` hook: + +```jsx +const { data, isLoading, error } = useCustomer({ + swrOptions: { + revalidateOnFocus: true, + }, +}) +``` + +### CommerceProvider + +This component adds the provider config and handlers to the context of your React tree for it's children. You can optionally pass the `locale` to it: + +```jsx +import { CommerceProvider } from '@framework' + +const App = ({ locale = 'en-US', children }) => { + return <CommerceProvider locale={locale}>{children}</CommerceProvider> +} +``` + +## Authentication Hooks + +### useSignup + +Returns a _signup_ function that can be used to sign up the current visitor: + +```jsx +import useSignup from '@framework/auth/use-signup' + +const SignupView = () => { + const signup = useSignup() + + const handleSignup = async () => { + await signup({ + email, + firstName, + lastName, + password, + }) + } + + return <form onSubmit={handleSignup}>{children}</form> +} +``` + +### useLogin + +Returns a _login_ function that can be used to sign in the current visitor into an existing customer: + +```jsx +import useLogin from '@framework/auth/use-login' + +const LoginView = () => { + const login = useLogin() + const handleLogin = async () => { + await login({ + email, + password, + }) + } + + return <form onSubmit={handleLogin}>{children}</form> +} +``` + +### useLogout + +Returns a _logout_ function that signs out the current customer when called. + +```jsx +import useLogout from '@framework/auth/use-logout' + +const LogoutButton = () => { + const logout = useLogout() + return ( + <button type="button" onClick={() => logout()}> + Logout + </button> + ) +} +``` + +## Customer Hooks + +### useCustomer + +Fetches and returns the data of the signed in customer: + +```jsx +import useCustomer from '@framework/customer/use-customer' + +const Profile = () => { + const { data, isLoading, error } = useCustomer() + + if (isLoading) return <p>Loading...</p> + if (error) return <p>{error.message}</p> + if (!data) return null + + return <div>Hello, {data.firstName}</div> +} +``` + +## Product Hooks + +### usePrice + +Helper hook to format price according to the commerce locale and currency code. It also handles discounts: + +```jsx +import useCart from '@framework/cart/use-cart' +import usePrice from '@framework/product/use-price' + +// ... +const { data } = useCart() +const { price, discount, basePrice } = usePrice( + data && { + amount: data.subtotalPrice, + currencyCode: data.currency.code, + // If `baseAmount` is used, a discount will be calculated + // baseAmount: number, + } +) +// ... +``` + +### useSearch + +Fetches and returns the products that match a set of filters: + +```jsx +import useSearch from '@framework/product/use-search' + +const SearchPage = ({ searchString, category, brand, sortStr }) => { + const { data } = useSearch({ + search: searchString || '', + categoryId: category?.entityId, + brandId: brand?.entityId, + sort: sortStr, + }) + + return ( + <Grid layout="normal"> + {data.products.map((product) => ( + <ProductCard key={product.path} product={product} /> + ))} + </Grid> + ) +} +``` + +## Cart Hooks + +### useCart + +Fetches and returns the data of the current cart: + +```jsx +import useCart from '@framework/cart/use-cart' + +const CartTotal = () => { + const { data, isLoading, isEmpty, error } = useCart() + + if (isLoading) return <p>Loading...</p> + if (error) return <p>{error.message}</p> + if (isEmpty) return <p>The cart is empty</p> + + return <p>The cart total is {data.totalPrice}</p> +} +``` + +### useAddItem + +Returns a function that adds a new item to the cart when called, if this is the first item it will create the cart: + +```jsx +import { useAddItem } from '@framework/cart' + +const AddToCartButton = ({ productId, variantId }) => { + const addItem = useAddItem() + + const addToCart = async () => { + await addItem({ + productId, + variantId, + }) + } + + return <button onClick={addToCart}>Add To Cart</button> +} +``` + +### useUpdateItem + +Returns a function that updates a current item in the cart when called, usually the quantity. + +```jsx +import { useUpdateItem } from '@framework/cart' + +const CartItemQuantity = ({ item }) => { + const [quantity, setQuantity] = useState(item.quantity) + const updateItem = useUpdateItem({ item }) + + const updateQuantity = async (e) => { + const val = e.target.value + + setQuantity(val) + await updateItem({ quantity: val }) + } + + return ( + <input + type="number" + max={99} + min={0} + value={quantity} + onChange={updateQuantity} + /> + ) +} +``` + +If the `quantity` is lower than 1 the item will be removed from the cart. + +### useRemoveItem + +Returns a function that removes an item in the cart when called: + +```jsx +import { useRemoveItem } from '@framework/cart' + +const RemoveButton = ({ item }) => { + const removeItem = useRemoveItem() + const handleRemove = async () => { + await removeItem(item) + } + + return <button onClick={handleRemove}>Remove</button> +} +``` + +## Wishlist Hooks + +Wishlist hooks work just like [cart hooks](#cart-hooks). Feel free to check how those work first. + +The example below shows how to use the `useWishlist`, `useAddItem` and `useRemoveItem` hooks: + +```jsx +import { useWishlist, useAddItem, useRemoveItem } from '@framework/wishlist' + +const WishlistButton = ({ productId, variant }) => { + const addItem = useAddItem() + const removeItem = useRemoveItem() + const { data, isLoading, isEmpty, error } = useWishlist() + + if (isLoading) return <p>Loading...</p> + if (error) return <p>{error.message}</p> + if (isEmpty) return <p>The wihslist is empty</p> + + const { data: customer } = useCustomer() + const itemInWishlist = data?.items?.find( + (item) => item.product_id === productId && item.variant_id === variant.id + ) + + const handleWishlistChange = async (e) => { + e.preventDefault() + if (!customer) return + + if (itemInWishlist) { + await removeItem({ id: itemInWishlist.id }) + } else { + await addItem({ + productId, + variantId: variant.id, + }) + } + } + + return ( + <button onClick={handleWishlistChange}> + <Heart fill={itemInWishlist ? 'var(--pink)' : 'none'} /> + </button> + ) +} +``` + +## Commerce API + +While commerce hooks focus on client side data fetching and interactions, the commerce API focuses on static content generation for pages and API endpoints in a Node.js context. + +> The commerce API is currently going through a refactor in https://github.com/vercel/commerce/pull/252 - We'll update the docs once the API is released. + +## More + +Feel free to read through the source for more usage, and check the commerce vercel demo and commerce repo for usage examples: ([demo.vercel.store](https://demo.vercel.store/)) ([repo](https://github.com/vercel/commerce)) diff --git a/framework/commerce/api/index.ts b/framework/commerce/api/index.ts new file mode 100644 index 00000000..77b2eeb7 --- /dev/null +++ b/framework/commerce/api/index.ts @@ -0,0 +1,34 @@ +import type { RequestInit, Response } from '@vercel/fetch' + +export interface CommerceAPIConfig { + locale?: string + commerceUrl: string + apiToken: string + cartCookie: string + cartCookieMaxAge: number + customerCookie: string + fetch<Data = any, Variables = any>( + query: string, + queryData?: CommerceAPIFetchOptions<Variables>, + fetchOptions?: RequestInit + ): Promise<GraphQLFetcherResult<Data>> +} + +export type GraphQLFetcher< + Data extends GraphQLFetcherResult = GraphQLFetcherResult, + Variables = any +> = ( + query: string, + queryData?: CommerceAPIFetchOptions<Variables>, + fetchOptions?: RequestInit +) => Promise<Data> + +export interface GraphQLFetcherResult<Data = any> { + data: Data + res: Response +} + +export interface CommerceAPIFetchOptions<Variables> { + variables?: Variables + preview?: boolean +} diff --git a/framework/commerce/auth/use-login.tsx b/framework/commerce/auth/use-login.tsx new file mode 100644 index 00000000..cc4cf6a7 --- /dev/null +++ b/framework/commerce/auth/use-login.tsx @@ -0,0 +1,19 @@ +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { MutationHook, HookFetcherFn } from '../utils/types' +import type { Provider } from '..' + +export type UseLogin< + H extends MutationHook<any, any, any> = MutationHook<null, {}, {}> +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn<null, {}> = mutationFetcher + +const fn = (provider: Provider) => provider.auth?.useLogin! + +const useLogin: UseLogin = (...args) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(...args) +} + +export default useLogin diff --git a/framework/commerce/auth/use-logout.tsx b/framework/commerce/auth/use-logout.tsx new file mode 100644 index 00000000..d0f7e3ae --- /dev/null +++ b/framework/commerce/auth/use-logout.tsx @@ -0,0 +1,19 @@ +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, MutationHook } from '../utils/types' +import type { Provider } from '..' + +export type UseLogout< + H extends MutationHook<any, any, any> = MutationHook<null> +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn<null> = mutationFetcher + +const fn = (provider: Provider) => provider.auth?.useLogout! + +const useLogout: UseLogout = (...args) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(...args) +} + +export default useLogout diff --git a/framework/commerce/auth/use-signup.tsx b/framework/commerce/auth/use-signup.tsx new file mode 100644 index 00000000..72e24220 --- /dev/null +++ b/framework/commerce/auth/use-signup.tsx @@ -0,0 +1,19 @@ +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, MutationHook } from '../utils/types' +import type { Provider } from '..' + +export type UseSignup< + H extends MutationHook<any, any, any> = MutationHook<null> +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn<null> = mutationFetcher + +const fn = (provider: Provider) => provider.auth?.useSignup! + +const useSignup: UseSignup = (...args) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(...args) +} + +export default useSignup diff --git a/framework/commerce/cart/use-add-item.tsx b/framework/commerce/cart/use-add-item.tsx new file mode 100644 index 00000000..32446465 --- /dev/null +++ b/framework/commerce/cart/use-add-item.tsx @@ -0,0 +1,23 @@ +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, MutationHook } from '../utils/types' +import type { Cart, CartItemBody, AddCartItemBody } from '../types' +import type { Provider } from '..' + +export type UseAddItem< + H extends MutationHook<any, any, any> = MutationHook<Cart, {}, CartItemBody> +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn< + Cart, + AddCartItemBody<CartItemBody> +> = mutationFetcher + +const fn = (provider: Provider) => provider.cart?.useAddItem! + +const useAddItem: UseAddItem = (...args) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(...args) +} + +export default useAddItem diff --git a/framework/commerce/cart/use-cart.tsx b/framework/commerce/cart/use-cart.tsx new file mode 100644 index 00000000..fbed715c --- /dev/null +++ b/framework/commerce/cart/use-cart.tsx @@ -0,0 +1,41 @@ +import Cookies from 'js-cookie' +import { useHook, useSWRHook } from '../utils/use-hook' +import type { HookFetcherFn, SWRHook } from '../utils/types' +import type { Cart } from '../types' +import { Provider, useCommerce } from '..' + +export type FetchCartInput = { + cartId?: Cart['id'] +} + +export type UseCart< + H extends SWRHook<any, any, any> = SWRHook< + Cart | null, + {}, + FetchCartInput, + { isEmpty?: boolean } + > +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn<Cart | null, FetchCartInput> = async ({ + options, + input: { cartId }, + fetch, +}) => { + return cartId ? await fetch({ ...options }) : null +} + +const fn = (provider: Provider) => provider.cart?.useCart! + +const useCart: UseCart = (input) => { + const hook = useHook(fn) + const { cartCookie } = useCommerce() + const fetcherFn = hook.fetcher ?? fetcher + const wrapper: typeof fetcher = (context) => { + context.input.cartId = Cookies.get(cartCookie) + return fetcherFn(context) + } + return useSWRHook({ ...hook, fetcher: wrapper })(input) +} + +export default useCart diff --git a/framework/commerce/cart/use-remove-item.tsx b/framework/commerce/cart/use-remove-item.tsx new file mode 100644 index 00000000..a9d1b37d --- /dev/null +++ b/framework/commerce/cart/use-remove-item.tsx @@ -0,0 +1,35 @@ +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, MutationHook } from '../utils/types' +import type { Cart, LineItem, RemoveCartItemBody } from '../types' +import type { Provider } from '..' + +/** + * Input expected by the action returned by the `useRemoveItem` hook + */ +export type RemoveItemInput = { + id: string +} + +export type UseRemoveItem< + H extends MutationHook<any, any, any> = MutationHook< + Cart | null, + { item?: LineItem }, + RemoveItemInput, + RemoveCartItemBody + > +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn< + Cart | null, + RemoveCartItemBody +> = mutationFetcher + +const fn = (provider: Provider) => provider.cart?.useRemoveItem! + +const useRemoveItem: UseRemoveItem = (input) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(input) +} + +export default useRemoveItem diff --git a/framework/commerce/cart/use-update-item.tsx b/framework/commerce/cart/use-update-item.tsx new file mode 100644 index 00000000..f8d0f1a4 --- /dev/null +++ b/framework/commerce/cart/use-update-item.tsx @@ -0,0 +1,38 @@ +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, MutationHook } from '../utils/types' +import type { Cart, CartItemBody, LineItem, UpdateCartItemBody } from '../types' +import type { Provider } from '..' + +/** + * Input expected by the action returned by the `useUpdateItem` hook + */ +export type UpdateItemInput<T extends CartItemBody> = T & { + id: string +} + +export type UseUpdateItem< + H extends MutationHook<any, any, any> = MutationHook< + Cart | null, + { + item?: LineItem + wait?: number + }, + UpdateItemInput<CartItemBody>, + UpdateCartItemBody<CartItemBody> + > +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn< + Cart | null, + UpdateCartItemBody<CartItemBody> +> = mutationFetcher + +const fn = (provider: Provider) => provider.cart?.useUpdateItem! + +const useUpdateItem: UseUpdateItem = (input) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(input) +} + +export default useUpdateItem diff --git a/framework/commerce/config.js b/framework/commerce/config.js new file mode 100644 index 00000000..2e999620 --- /dev/null +++ b/framework/commerce/config.js @@ -0,0 +1,74 @@ +/** + * This file is expected to be used in next.config.js only + */ + +const path = require('path') +const fs = require('fs') +const merge = require('deepmerge') +const prettier = require('prettier') + +const PROVIDERS = [ + 'bigcommerce', + 'shopify', + 'swell', + 'vendure', + 'reactioncommerce', +] + +function getProviderName() { + return ( + process.env.COMMERCE_PROVIDER || + (process.env.BIGCOMMERCE_STOREFRONT_API_URL + ? 'bigcommerce' + : process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN + ? 'shopify' + : process.env.NEXT_PUBLIC_SWELL_STORE_ID + ? 'swell' + : null) + ) +} + +function withCommerceConfig(nextConfig = {}) { + const commerce = nextConfig.commerce || {} + const name = commerce.provider || getProviderName() + + if (!name) { + throw new Error( + `The commerce provider is missing, please add a valid provider name or its environment variables` + ) + } + if (!PROVIDERS.includes(name)) { + throw new Error( + `The commerce provider "${name}" can't be found, please use one of "${PROVIDERS.join( + ', ' + )}"` + ) + } + + const commerceNextConfig = require(path.join('../', name, 'next.config')) + const config = merge(commerceNextConfig, nextConfig) + + config.env = config.env || {} + + Object.entries(config.commerce.features).forEach(([k, v]) => { + if (v) config.env[`COMMERCE_${k.toUpperCase()}_ENABLED`] = true + }) + + // Update paths in `tsconfig.json` to point to the selected provider + if (config.commerce.updateTSConfig !== false) { + const tsconfigPath = path.join(process.cwd(), 'tsconfig.json') + const tsconfig = require(tsconfigPath) + + tsconfig.compilerOptions.paths['@framework'] = [`framework/${name}`] + tsconfig.compilerOptions.paths['@framework/*'] = [`framework/${name}/*`] + + fs.writeFileSync( + tsconfigPath, + prettier.format(JSON.stringify(tsconfig), { parser: 'json' }) + ) + } + + return config +} + +module.exports = { withCommerceConfig, getProviderName } diff --git a/framework/commerce/customer/use-customer.tsx b/framework/commerce/customer/use-customer.tsx new file mode 100644 index 00000000..5d6416a4 --- /dev/null +++ b/framework/commerce/customer/use-customer.tsx @@ -0,0 +1,20 @@ +import { useHook, useSWRHook } from '../utils/use-hook' +import { SWRFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, SWRHook } from '../utils/types' +import type { Customer } from '../types' +import { Provider } from '..' + +export type UseCustomer< + H extends SWRHook<any, any, any> = SWRHook<Customer | null> +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn<Customer | null, any> = SWRFetcher + +const fn = (provider: Provider) => provider.customer?.useCustomer! + +const useCustomer: UseCustomer = (input) => { + const hook = useHook(fn) + return useSWRHook({ fetcher, ...hook })(input) +} + +export default useCustomer diff --git a/framework/commerce/index.tsx b/framework/commerce/index.tsx new file mode 100644 index 00000000..07bf74a2 --- /dev/null +++ b/framework/commerce/index.tsx @@ -0,0 +1,88 @@ +import { + ReactNode, + MutableRefObject, + createContext, + useContext, + useMemo, + useRef, +} from 'react' +import { Fetcher, SWRHook, MutationHook } from './utils/types' +import type { FetchCartInput } from './cart/use-cart' +import type { Cart, Wishlist, Customer, SearchProductsData } from './types' + +const Commerce = createContext<CommerceContextValue<any> | {}>({}) + +export type Provider = CommerceConfig & { + fetcher: Fetcher + cart?: { + useCart?: SWRHook<Cart | null, any, FetchCartInput> + useAddItem?: MutationHook<any, any, any> + useUpdateItem?: MutationHook<any, any, any> + useRemoveItem?: MutationHook<any, any, any> + } + wishlist?: { + useWishlist?: SWRHook<Wishlist | null, any, any> + useAddItem?: MutationHook<any, any, any> + useRemoveItem?: MutationHook<any, any, any> + } + customer?: { + useCustomer?: SWRHook<Customer | null, any, any> + } + products?: { + useSearch?: SWRHook<SearchProductsData, any, any> + } + auth?: { + useSignup?: MutationHook<any, any, any> + useLogin?: MutationHook<any, any, any> + useLogout?: MutationHook<any, any, any> + } +} + +export type CommerceProps<P extends Provider> = { + children?: ReactNode + provider: P + config: CommerceConfig +} + +export type CommerceConfig = Omit< + CommerceContextValue<any>, + 'providerRef' | 'fetcherRef' +> + +export type CommerceContextValue<P extends Provider> = { + providerRef: MutableRefObject<P> + fetcherRef: MutableRefObject<Fetcher> + locale: string + cartCookie: string +} + +export function CommerceProvider<P extends Provider>({ + provider, + children, + config, +}: CommerceProps<P>) { + if (!config) { + throw new Error('CommerceProvider requires a valid config object') + } + + const providerRef = useRef(provider) + // TODO: Remove the fetcherRef + const fetcherRef = useRef(provider.fetcher) + // Because the config is an object, if the parent re-renders this provider + // will re-render every consumer unless we memoize the config + const cfg = useMemo( + () => ({ + providerRef, + fetcherRef, + locale: config.locale, + cartCookie: config.cartCookie, + }), + [config.locale, config.cartCookie] + ) + + return <Commerce.Provider value={cfg}>{children}</Commerce.Provider> +} + +export function useCommerce<P extends Provider>() { + return useContext(Commerce) as CommerceContextValue<P> +} diff --git a/framework/commerce/new-provider.md b/framework/commerce/new-provider.md new file mode 100644 index 00000000..4051c0f0 --- /dev/null +++ b/framework/commerce/new-provider.md @@ -0,0 +1,239 @@ +# Adding a new Commerce Provider + +A commerce provider is a headless e-commerce platform that integrates with the [Commerce Framework](./README.md). Right now we have the following providers: + +- BigCommerce ([framework/bigcommerce](../bigcommerce)) +- Shopify ([framework/shopify](../shopify)) + +Adding a commerce provider means adding a new folder in `framework` with a folder structure like the next one: + +- `api` + - index.ts +- `product` + - usePrice + - useSearch + - getProduct + - getAllProducts +- `wishlist` + - useWishlist + - useAddItem + - useRemoveItem +- `auth` + - useLogin + - useLogout + - useSignup +- `customer` + - useCustomer + - getCustomerId + - getCustomerWistlist +- `cart` + - useCart + - useAddItem + - useRemoveItem + - useUpdateItem +- `env.template` +- `index.ts` +- `provider.ts` +- `commerce.config.json` +- `next.config.js` +- `README.md` + +`provider.ts` exports a provider object with handlers for the [Commerce Hooks](./README.md#commerce-hooks) and `api/index.ts` exports a Node.js provider for the [Commerce API](./README.md#commerce-api) + +> **Important:** We use TypeScript for every provider and expect its usage for every new one. + +The app imports from the provider directly instead of the core commerce folder (`framework/commerce`), but all providers are interchangeable and to achieve it every provider always has to implement the core types and helpers. + +The provider folder should only depend on `framework/commerce` and dependencies in the main `package.json`. In the future we'll move the `framework` folder to a package that can be shared easily for multiple apps. + +## Adding the provider hooks + +Using BigCommerce as an example. The first thing to do is export a `CommerceProvider` component that includes a `provider` object with all the handlers that can be used for hooks: + +```tsx +import type { ReactNode } from 'react' +import { + CommerceConfig, + CommerceProvider as CoreCommerceProvider, + useCommerce as useCoreCommerce, +} from '@commerce' +import { bigcommerceProvider, BigcommerceProvider } from './provider' + +export { bigcommerceProvider } +export type { BigcommerceProvider } + +export const bigcommerceConfig: CommerceConfig = { + locale: 'en-us', + cartCookie: 'bc_cartId', +} + +export type BigcommerceConfig = Partial<CommerceConfig> + +export type BigcommerceProps = { + children?: ReactNode + locale: string +} & BigcommerceConfig + +export function CommerceProvider({ children, ...config }: BigcommerceProps) { + return ( + <CoreCommerceProvider + provider={bigcommerceProvider} + config={{ ...bigcommerceConfig, ...config }} + > + {children} + </CoreCommerceProvider> + ) +} + +export const useCommerce = () => useCoreCommerce<BigcommerceProvider>() +``` + +The exported types and components extend from the core ones exported by `@commerce`, which refers to `framework/commerce`. + +The `bigcommerceProvider` object looks like this: + +```tsx +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 useWishlist } from './wishlist/use-wishlist' +import { handler as useWishlistAddItem } from './wishlist/use-add-item' +import { handler as useWishlistRemoveItem } from './wishlist/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' + +import fetcher from './fetcher' + +export const bigcommerceProvider = { + locale: 'en-us', + cartCookie: 'bc_cartId', + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + wishlist: { + useWishlist, + useAddItem: useWishlistAddItem, + useRemoveItem: useWishlistRemoveItem, + }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, +} + +export type BigcommerceProvider = typeof bigcommerceProvider +``` + +The provider object, in this case `bigcommerceProvider`, has to match the `Provider` type defined in [framework/commerce](./index.ts). + +A hook handler, like `useCart`, looks like this: + +```tsx +import { useMemo } from 'react' +import { SWRHook } from '@commerce/utils/types' +import useCart, { UseCart, FetchCartInput } from '@commerce/cart/use-cart' +import { normalizeCart } from '../lib/normalize' +import type { Cart } from '../types' + +export default useCart as UseCart<typeof handler> + +export const handler: SWRHook< + Cart | null, + {}, + FetchCartInput, + { isEmpty?: boolean } +> = { + fetchOptions: { + url: '/api/bigcommerce/cart', + method: 'GET', + }, + async fetcher({ input: { cartId }, options, fetch }) { + const data = cartId ? await fetch(options) : null + return data && normalizeCart(data) + }, + useHook: ({ useData }) => (input) => { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} +``` + +In the case of data fetching hooks like `useCart` each handler has to implement the `SWRHook` type that's defined in the core types. For mutations it's the `MutationHook`, e.g for `useAddItem`: + +```tsx +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' +import { normalizeCart } from '../lib/normalize' +import type { + Cart, + BigcommerceCart, + CartItemBody, + AddCartItemBody, +} from '../types' +import useCart from './use-cart' + +export default useAddItem as UseAddItem<typeof handler> + +export const handler: MutationHook<Cart, {}, CartItemBody> = { + fetchOptions: { + url: '/api/bigcommerce/cart', + method: 'POST', + }, + async fetcher({ input: item, options, fetch }) { + if ( + item.quantity && + (!Number.isInteger(item.quantity) || item.quantity! < 1) + ) { + throw new CommerceError({ + message: 'The item quantity has to be a valid integer greater than 0', + }) + } + + const data = await fetch<BigcommerceCart, AddCartItemBody>({ + ...options, + body: { item }, + }) + + return normalizeCart(data) + }, + useHook: ({ fetch }) => () => { + const { mutate } = useCart() + + return useCallback( + async function addItem(input) { + const data = await fetch({ input }) + await mutate(data, false) + return data + }, + [fetch, mutate] + ) + }, +} +``` + +## Adding the Node.js provider API + +TODO + +> The commerce API is currently going through a refactor in https://github.com/vercel/commerce/pull/252 - We'll update the docs once the API is released. diff --git a/framework/commerce/product/use-price.tsx b/framework/commerce/product/use-price.tsx new file mode 100644 index 00000000..9c09e348 --- /dev/null +++ b/framework/commerce/product/use-price.tsx @@ -0,0 +1,64 @@ +import { useMemo } from 'react' +import { useCommerce } from '..' + +export function formatPrice({ + amount, + currencyCode, + locale, +}: { + amount: number + currencyCode: string + locale: string +}) { + const formatCurrency = new Intl.NumberFormat(locale, { + style: 'currency', + currency: currencyCode, + }) + + return formatCurrency.format(amount) +} + +export function formatVariantPrice({ + amount, + baseAmount, + currencyCode, + locale, +}: { + baseAmount: number + amount: number + currencyCode: string + locale: string +}) { + const hasDiscount = baseAmount > amount + const formatDiscount = new Intl.NumberFormat(locale, { style: 'percent' }) + const discount = hasDiscount + ? formatDiscount.format((baseAmount - amount) / baseAmount) + : null + + const price = formatPrice({ amount, currencyCode, locale }) + const basePrice = hasDiscount + ? formatPrice({ amount: baseAmount, currencyCode, locale }) + : null + + return { price, basePrice, discount } +} + +export default function usePrice( + data?: { + amount: number + baseAmount?: number + currencyCode: string + } | null +) { + const { amount, baseAmount, currencyCode } = data ?? {} + const { locale } = useCommerce() + const value = useMemo(() => { + if (typeof amount !== 'number' || !currencyCode) return '' + + return baseAmount + ? formatVariantPrice({ amount, baseAmount, currencyCode, locale }) + : formatPrice({ amount, currencyCode, locale }) + }, [amount, baseAmount, currencyCode]) + + return typeof value === 'string' ? { price: value } : value +} diff --git a/framework/commerce/product/use-search.tsx b/framework/commerce/product/use-search.tsx new file mode 100644 index 00000000..d2b78204 --- /dev/null +++ b/framework/commerce/product/use-search.tsx @@ -0,0 +1,20 @@ +import { useHook, useSWRHook } from '../utils/use-hook' +import { SWRFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, SWRHook } from '../utils/types' +import type { SearchProductsData } from '../types' +import { Provider } from '..' + +export type UseSearch< + H extends SWRHook<any, any, any> = SWRHook<SearchProductsData> +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn<SearchProductsData, any> = SWRFetcher + +const fn = (provider: Provider) => provider.products?.useSearch! + +const useSearch: UseSearch = (input) => { + const hook = useHook(fn) + return useSWRHook({ fetcher, ...hook })(input) +} + +export default useSearch diff --git a/framework/commerce/types.ts b/framework/commerce/types.ts new file mode 100644 index 00000000..b36a3c26 --- /dev/null +++ b/framework/commerce/types.ts @@ -0,0 +1,204 @@ +import type { Wishlist as BCWishlist } from '../bigcommerce/api/wishlist' +import type { Customer as BCCustomer } from '../bigcommerce/api/customers' +import type { SearchProductsData as BCSearchProductsData } from '../bigcommerce/api/catalog/products' + +export type Discount = { + // The value of the discount, can be an amount or percentage + value: number +} + +export type LineItem = { + id: string + variantId: string + productId: string + name: string + quantity: number + discounts: Discount[] + // A human-friendly unique string automatically generated from the product’s name + path: string + variant: ProductVariant +} + +export type Measurement = { + value: number + unit: 'KILOGRAMS' | 'GRAMS' | 'POUNDS' | 'OUNCES' +} + +export type Image = { + url: string + altText?: string + width?: number + height?: number +} + +export type ProductVariant = { + id: string + // The SKU (stock keeping unit) associated with the product variant. + sku: string + // The product variant’s title, or the product's name. + name: string + // Whether a customer needs to provide a shipping address when placing + // an order for the product variant. + requiresShipping: boolean + // The product variant’s price after all discounts are applied. + price: number + // Product variant’s price, as quoted by the manufacturer/distributor. + listPrice: number + // Image associated with the product variant. Falls back to the product image + // if no image is available. + image?: Image + // Indicates whether this product variant is in stock. + isInStock?: boolean + // Indicates if the product variant is available for sale. + availableForSale?: boolean + // The variant's weight. If a weight was not explicitly specified on the + // variant this will be the product's weight. + weight?: Measurement + // The variant's height. If a height was not explicitly specified on the + // variant, this will be the product's height. + height?: Measurement + // The variant's width. If a width was not explicitly specified on the + // variant, this will be the product's width. + width?: Measurement + // The variant's depth. If a depth was not explicitly specified on the + // variant, this will be the product's depth. + depth?: Measurement + options: ProductOption[] +} + +// Shopping cart, a.k.a Checkout +export type Cart = { + id: string + // ID of the customer to which the cart belongs. + customerId?: string + // The email assigned to this cart + email?: string + // The date and time when the cart was created. + createdAt: string + // The currency used for this cart + currency: { code: string } + // Specifies if taxes are included in the line items. + taxesIncluded: boolean + lineItems: LineItem[] + // The sum of all the prices of all the items in the cart. + // Duties, taxes, shipping and discounts excluded. + lineItemsSubtotalPrice: number + // Price of the cart before duties, shipping and taxes. + subtotalPrice: number + // The sum of all the prices of all the items in the cart. + // Duties, taxes and discounts included. + totalPrice: number + // Discounts that have been applied on the cart. + discounts?: Discount[] +} + +// TODO: Properly define this type +export interface Wishlist extends BCWishlist {} + +// TODO: Properly define this type +export interface Customer extends BCCustomer {} + +// TODO: Properly define this type +export interface SearchProductsData extends BCSearchProductsData {} + +/** + * Cart mutations + */ + +// Base cart item body used for cart mutations +export type CartItemBody = { + variantId: string + productId?: string + quantity?: number + pricing?: { + amount: number + currencyCode: string + } +} + +// Body used by the `getCart` operation handler +export type GetCartHandlerBody = { + cartId?: string +} + +// Body used by the add item to cart operation +export type AddCartItemBody<T extends CartItemBody> = { + item: T +} + +// Body expected by the add item to cart operation handler +export type AddCartItemHandlerBody<T extends CartItemBody> = Partial< + AddCartItemBody<T> +> & { + cartId?: string +} + +// Body used by the update cart item operation +export type UpdateCartItemBody<T extends CartItemBody> = { + itemId: string + item: T +} + +// Body expected by the update cart item operation handler +export type UpdateCartItemHandlerBody<T extends CartItemBody> = Partial< + UpdateCartItemBody<T> +> & { + cartId?: string +} + +// Body used by the remove cart item operation +export type RemoveCartItemBody = { + itemId: string +} + +// Body expected by the remove cart item operation handler +export type RemoveCartItemHandlerBody = Partial<RemoveCartItemBody> & { + cartId?: string +} + +/** + * Temporal types + */ + +interface Entity { + id: string | number + [prop: string]: any +} + +export interface Product extends Entity { + name: string + description: string + descriptionHtml?: string + slug?: string + path?: string + images: ProductImage[] + variants: ProductVariant[] + price: ProductPrice + options: ProductOption[] + sku?: string +} + +export interface ProductOption extends Entity { + displayName: string + values: ProductOptionValues[] +} + +export interface ProductOptionValues { + label: string + hexColors?: string[] +} + +interface ProductImage { + url: string + alt?: string +} + +interface ProductPrice { + value: number + currencyCode: 'USD' | 'ARS' | string | undefined + retailPrice?: number + salePrice?: number + listPrice?: number + extendedSalePrice?: number + extendedListPrice?: number +} diff --git a/framework/commerce/utils/default-fetcher.ts b/framework/commerce/utils/default-fetcher.ts new file mode 100644 index 00000000..493a9b5f --- /dev/null +++ b/framework/commerce/utils/default-fetcher.ts @@ -0,0 +1,12 @@ +import type { HookFetcherFn } from './types' + +export const SWRFetcher: HookFetcherFn<any, any> = ({ options, fetch }) => + fetch(options) + +export const mutationFetcher: HookFetcherFn<any, any> = ({ + input, + options, + fetch, +}) => fetch({ ...options, body: input }) + +export default SWRFetcher diff --git a/framework/commerce/utils/define-property.ts b/framework/commerce/utils/define-property.ts new file mode 100644 index 00000000..e8973522 --- /dev/null +++ b/framework/commerce/utils/define-property.ts @@ -0,0 +1,37 @@ +// Taken from https://fettblog.eu/typescript-assertion-signatures/ + +type InferValue<Prop extends PropertyKey, Desc> = Desc extends { + get(): any + value: any +} + ? never + : Desc extends { value: infer T } + ? Record<Prop, T> + : Desc extends { get(): infer T } + ? Record<Prop, T> + : never + +type DefineProperty< + Prop extends PropertyKey, + Desc extends PropertyDescriptor +> = Desc extends { writable: any; set(val: any): any } + ? never + : Desc extends { writable: any; get(): any } + ? never + : Desc extends { writable: false } + ? Readonly<InferValue<Prop, Desc>> + : Desc extends { writable: true } + ? InferValue<Prop, Desc> + : Readonly<InferValue<Prop, Desc>> + +export default function defineProperty< + Obj extends object, + Key extends PropertyKey, + PDesc extends PropertyDescriptor +>( + obj: Obj, + prop: Key, + val: PDesc +): asserts obj is Obj & DefineProperty<Key, PDesc> { + Object.defineProperty(obj, prop, val) +} diff --git a/framework/commerce/utils/errors.ts b/framework/commerce/utils/errors.ts new file mode 100644 index 00000000..f4ab9fb9 --- /dev/null +++ b/framework/commerce/utils/errors.ts @@ -0,0 +1,48 @@ +export type ErrorData = { + message: string + code?: string +} + +export type ErrorProps = { + code?: string +} & ( + | { message: string; errors?: never } + | { message?: never; errors: ErrorData[] } +) + +export class CommerceError extends Error { + code?: string + errors: ErrorData[] + + constructor({ message, code, errors }: ErrorProps) { + const error: ErrorData = message + ? { message, ...(code ? { code } : {}) } + : errors![0] + + super(error.message) + this.errors = message ? [error] : errors! + + if (error.code) this.code = error.code + } +} + +// Used for errors that come from a bad implementation of the hooks +export class ValidationError extends CommerceError { + constructor(options: ErrorProps) { + super(options) + this.code = 'validation_error' + } +} + +export class FetcherError extends CommerceError { + status: number + + constructor( + options: { + status: number + } & ErrorProps + ) { + super(options) + this.status = options.status + } +} diff --git a/framework/commerce/utils/types.ts b/framework/commerce/utils/types.ts new file mode 100644 index 00000000..852afb20 --- /dev/null +++ b/framework/commerce/utils/types.ts @@ -0,0 +1,131 @@ +import type { ConfigInterface } from 'swr' +import type { CommerceError } from './errors' +import type { ResponseState } from './use-data' + +/** + * Returns the properties in T with the properties in type K, overriding properties defined in T + */ +export type Override<T, K> = Omit<T, keyof K> & K + +/** + * Returns the properties in T with the properties in type K changed from optional to required + */ +export type PickRequired<T, K extends keyof T> = Omit<T, K> & + { + [P in K]-?: NonNullable<T[P]> + } + +/** + * Core fetcher added by CommerceProvider + */ +export type Fetcher<T = any, B = any> = ( + options: FetcherOptions<B> +) => T | Promise<T> + +export type FetcherOptions<Body = any> = { + url?: string + query?: string + method?: string + variables?: any + body?: Body +} + +export type HookFetcher<Data, Input = null, Result = any> = ( + options: HookFetcherOptions | null, + input: Input, + fetch: <T = Result, Body = any>(options: FetcherOptions<Body>) => Promise<T> +) => Data | Promise<Data> + +export type HookFetcherFn<Data, Input = undefined, Result = any, Body = any> = ( + context: HookFetcherContext<Input, Result, Body> +) => Data | Promise<Data> + +export type HookFetcherContext<Input = undefined, Result = any, Body = any> = { + options: HookFetcherOptions + input: Input + fetch: <T = Result, B = Body>(options: FetcherOptions<B>) => Promise<T> +} + +export type HookFetcherOptions = { method?: string } & ( + | { query: string; url?: string } + | { query?: string; url: string } +) + +export type HookInputValue = string | number | boolean | undefined + +export type HookSWRInput = [string, HookInputValue][] + +export type HookFetchInput = { [k: string]: HookInputValue } + +export type HookFunction< + Input extends { [k: string]: unknown } | null, + T +> = keyof Input extends never + ? () => T + : Partial<Input> extends Input + ? (input?: Input) => T + : (input: Input) => T + +export type SWRHook< + // Data obj returned by the hook and fetch operation + Data, + // Input expected by the hook + Input extends { [k: string]: unknown } = {}, + // Input expected before doing a fetch operation + FetchInput extends HookFetchInput = {}, + // Custom state added to the response object of SWR + State = {} +> = { + useHook( + context: SWRHookContext<Data, FetchInput> + ): HookFunction< + Input & { swrOptions?: SwrOptions<Data, FetchInput> }, + ResponseState<Data> & State + > + fetchOptions: HookFetcherOptions + fetcher?: HookFetcherFn<Data, FetchInput> +} + +export type SWRHookContext< + Data, + FetchInput extends { [k: string]: unknown } = {} +> = { + useData(context?: { + input?: HookFetchInput | HookSWRInput + swrOptions?: SwrOptions<Data, FetchInput> + }): ResponseState<Data> +} + +export type MutationHook< + // Data obj returned by the hook and fetch operation + Data, + // Input expected by the hook + Input extends { [k: string]: unknown } = {}, + // Input expected by the action returned by the hook + ActionInput extends { [k: string]: unknown } = {}, + // Input expected before doing a fetch operation + FetchInput extends { [k: string]: unknown } = ActionInput +> = { + useHook( + context: MutationHookContext<Data, FetchInput> + ): HookFunction<Input, HookFunction<ActionInput, Data | Promise<Data>>> + fetchOptions: HookFetcherOptions + fetcher?: HookFetcherFn<Data, FetchInput> +} + +export type MutationHookContext< + Data, + FetchInput extends { [k: string]: unknown } | null = {} +> = { + fetch: keyof FetchInput extends never + ? () => Data | Promise<Data> + : Partial<FetchInput> extends FetchInput + ? (context?: { input?: FetchInput }) => Data | Promise<Data> + : (context: { input: FetchInput }) => Data | Promise<Data> +} + +export type SwrOptions<Data, Input = null, Result = any> = ConfigInterface< + Data, + CommerceError, + HookFetcher<Data, Input, Result> +> diff --git a/framework/commerce/utils/use-data.tsx b/framework/commerce/utils/use-data.tsx new file mode 100644 index 00000000..9224b612 --- /dev/null +++ b/framework/commerce/utils/use-data.tsx @@ -0,0 +1,77 @@ +import useSWR, { responseInterface } from 'swr' +import type { + HookSWRInput, + HookFetchInput, + Fetcher, + SwrOptions, + HookFetcherOptions, + HookFetcherFn, +} from './types' +import defineProperty from './define-property' +import { CommerceError } from './errors' + +export type ResponseState<Result> = responseInterface<Result, CommerceError> & { + isLoading: boolean +} + +export type UseData = <Data = any, FetchInput extends HookFetchInput = {}>( + options: { + fetchOptions: HookFetcherOptions + fetcher: HookFetcherFn<Data, FetchInput> + }, + input: HookFetchInput | HookSWRInput, + fetcherFn: Fetcher, + swrOptions?: SwrOptions<Data, FetchInput> +) => ResponseState<Data> + +const useData: UseData = (options, input, fetcherFn, swrOptions) => { + const hookInput = Array.isArray(input) ? input : Object.entries(input) + const fetcher = async ( + url: string, + query?: string, + method?: string, + ...args: any[] + ) => { + try { + return await options.fetcher({ + options: { url, query, method }, + // Transform the input array into an object + input: args.reduce((obj, val, i) => { + obj[hookInput[i][0]!] = val + return obj + }, {}), + fetch: fetcherFn, + }) + } catch (error) { + // SWR will not log errors, but any error that's not an instance + // of CommerceError is not welcomed by this hook + if (!(error instanceof CommerceError)) { + console.error(error) + } + throw error + } + } + const response = useSWR( + () => { + const opts = options.fetchOptions + return opts + ? [opts.url, opts.query, opts.method, ...hookInput.map((e) => e[1])] + : null + }, + fetcher, + swrOptions + ) + + if (!('isLoading' in response)) { + defineProperty(response, 'isLoading', { + get() { + return response.data === undefined + }, + enumerable: true, + }) + } + + return response +} + +export default useData diff --git a/framework/commerce/utils/use-hook.ts b/framework/commerce/utils/use-hook.ts new file mode 100644 index 00000000..da3431e3 --- /dev/null +++ b/framework/commerce/utils/use-hook.ts @@ -0,0 +1,50 @@ +import { useCallback } from 'react' +import { Provider, useCommerce } from '..' +import type { MutationHook, PickRequired, SWRHook } from './types' +import useData from './use-data' + +export function useFetcher() { + const { providerRef, fetcherRef } = useCommerce() + return providerRef.current.fetcher ?? fetcherRef.current +} + +export function useHook< + P extends Provider, + H extends MutationHook<any, any, any> | SWRHook<any, any, any> +>(fn: (provider: P) => H) { + const { providerRef } = useCommerce<P>() + const provider = providerRef.current + return fn(provider) +} + +export function useSWRHook<H extends SWRHook<any, any, any>>( + hook: PickRequired<H, 'fetcher'> +) { + const fetcher = useFetcher() + + return hook.useHook({ + useData(ctx) { + const response = useData(hook, ctx?.input ?? [], fetcher, ctx?.swrOptions) + return response + }, + }) +} + +export function useMutationHook<H extends MutationHook<any, any, any>>( + hook: PickRequired<H, 'fetcher'> +) { + const fetcher = useFetcher() + + return hook.useHook({ + fetch: useCallback( + ({ input } = {}) => { + return hook.fetcher({ + input, + options: hook.fetchOptions, + fetch: fetcher, + }) + }, + [fetcher, hook.fetchOptions] + ), + }) +} diff --git a/framework/commerce/wishlist/index.ts b/framework/commerce/wishlist/index.ts new file mode 100644 index 00000000..241af3c7 --- /dev/null +++ b/framework/commerce/wishlist/index.ts @@ -0,0 +1,3 @@ +export { default as useAddItem } from './use-add-item' +export { default as useWishlist } from './use-wishlist' +export { default as useRemoveItem } from './use-remove-item' diff --git a/framework/commerce/wishlist/use-add-item.tsx b/framework/commerce/wishlist/use-add-item.tsx new file mode 100644 index 00000000..11c8cc24 --- /dev/null +++ b/framework/commerce/wishlist/use-add-item.tsx @@ -0,0 +1,19 @@ +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { MutationHook } from '../utils/types' +import type { Provider } from '..' + +export type UseAddItem< + H extends MutationHook<any, any, any> = MutationHook<any, {}, {}> +> = ReturnType<H['useHook']> + +export const fetcher = mutationFetcher + +const fn = (provider: Provider) => provider.wishlist?.useAddItem! + +const useAddItem: UseAddItem = (...args) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(...args) +} + +export default useAddItem diff --git a/framework/commerce/wishlist/use-remove-item.tsx b/framework/commerce/wishlist/use-remove-item.tsx new file mode 100644 index 00000000..c8c34a5a --- /dev/null +++ b/framework/commerce/wishlist/use-remove-item.tsx @@ -0,0 +1,28 @@ +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, MutationHook } from '../utils/types' +import type { Provider } from '..' + +export type RemoveItemInput = { + id: string | number +} + +export type UseRemoveItem< + H extends MutationHook<any, any, any> = MutationHook< + any | null, + { wishlist?: any }, + RemoveItemInput, + {} + > +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn<any | null, {}> = mutationFetcher + +const fn = (provider: Provider) => provider.wishlist?.useRemoveItem! + +const useRemoveItem: UseRemoveItem = (input) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(input) +} + +export default useRemoveItem diff --git a/framework/commerce/wishlist/use-wishlist.tsx b/framework/commerce/wishlist/use-wishlist.tsx new file mode 100644 index 00000000..7a93b20b --- /dev/null +++ b/framework/commerce/wishlist/use-wishlist.tsx @@ -0,0 +1,25 @@ +import { useHook, useSWRHook } from '../utils/use-hook' +import { SWRFetcher } from '../utils/default-fetcher' +import type { HookFetcherFn, SWRHook } from '../utils/types' +import type { Wishlist } from '../types' +import type { Provider } from '..' + +export type UseWishlist< + H extends SWRHook<any, any, any> = SWRHook< + Wishlist | null, + { includeProducts?: boolean }, + { customerId?: number; includeProducts: boolean }, + { isEmpty?: boolean } + > +> = ReturnType<H['useHook']> + +export const fetcher: HookFetcherFn<Wishlist | null, any> = SWRFetcher + +const fn = (provider: Provider) => provider.wishlist?.useWishlist! + +const useWishlist: UseWishlist = (input) => { + const hook = useHook(fn) + return useSWRHook({ fetcher, ...hook })(input) +} + +export default useWishlist diff --git a/framework/reactioncommerce/.env.template b/framework/reactioncommerce/.env.template new file mode 100644 index 00000000..c9e15c2d --- /dev/null +++ b/framework/reactioncommerce/.env.template @@ -0,0 +1,2 @@ +REACTION_API_DOMAIN= +REACTION_SHOP_ID= diff --git a/framework/reactioncommerce/README.md b/framework/reactioncommerce/README.md new file mode 100644 index 00000000..fc6a70ce --- /dev/null +++ b/framework/reactioncommerce/README.md @@ -0,0 +1,260 @@ +## Table of Contents + +- [Getting Started](#getting-started) + - [Modifications](#modifications) + - [Adding item to Cart](#adding-item-to-cart) + - [Proceed to Checkout](#proceed-to-checkout) +- [General Usage](#general-usage) + - [CommerceProvider](#commerceprovider) + - [useCommerce](#usecommerce) +- [Hooks](#hooks) + - [usePrice](#useprice) + - [useAddItem](#useadditem) + - [useRemoveItem](#useremoveitem) + - [useUpdateItem](#useupdateitem) +- [APIs](#apis) + - [getProduct](#getproduct) + - [getAllProducts](#getallproducts) + - [getAllCollections](#getallcollections) + - [getAllPages](#getallpages) + +# Shopify Storefront Data Hooks + +Collection of hooks and data fetching functions to integrate Shopify in a React application. Designed to work with [Next.js Commerce](https://demo.vercel.store/). + +## Getting Started + +1. Install dependencies: + +``` +yarn install shopify-buy +yarn install -D @types/shopify-buy +``` + +3. Environment variables need to be set: + +``` +SHOPIFY_STORE_DOMAIN= +SHOPIFY_STOREFRONT_ACCESS_TOKEN= +NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN= +NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN= +``` + +4. Point the framework to `shopify` by updating `tsconfig.json`: + +``` +"@framework/*": ["framework/shopify/*"], +"@framework": ["framework/shopify"] +``` + +### Modifications + +These modifications are temporarily until contributions are made to remove them. + +#### Adding item to Cart + +```js +// components/product/ProductView/ProductView.tsx +const ProductView: FC<Props> = ({ product }) => { + const addToCart = async () => { + setLoading(true) + try { + await addItem({ + productId: product.id, + variantId: variant ? variant.id : product.variants[0].id, + }) + openSidebar() + setLoading(false) + } catch (err) { + setLoading(false) + } + } +} +``` + +#### Proceed to Checkout + +```js +// components/cart/CartSidebarView/CartSidebarView.tsx +import { useCommerce } from '@framework' + +const CartSidebarView: FC = () => { + const { checkout } = useCommerce() + return ( + <Button href={checkout.webUrl} Component="a" width="100%"> + Proceed to Checkout + </Button> + ) +} +``` + +## General Usage + +### CommerceProvider + +Provider component that creates the commerce context for children. + +```js +import { CommerceProvider } from '@framework' + +const App = ({ children }) => { + return <CommerceProvider locale={locale}>{children}</CommerceProvider> +} + +export default App +``` + +### useCommerce + +Returns the configs that are defined in the nearest `CommerceProvider`. Also provides access to Shopify's `checkout` and `shop`. + +```js +import { useCommerce } from 'nextjs-commerce-shopify' + +const { checkout, shop } = useCommerce() +``` + +- `checkout`: The information required to checkout items and pay ([Documentation](https://shopify.dev/docs/storefront-api/reference/checkouts/checkout)). +- `shop`: Represents a collection of the general settings and information about the shop ([Documentation](https://shopify.dev/docs/storefront-api/reference/online-store/shop/index)). + +## Hooks + +### usePrice + +Display the product variant price according to currency and locale. + +```js +import usePrice from '@framework/product/use-price' + +const { price } = usePrice({ + amount, +}) +``` + +Takes in either `amount` or `variant`: + +- `amount`: A price value for a particular item if the amount is known. +- `variant`: A shopify product variant. Price will be extracted from the variant. + +### useAddItem + +```js +import { useAddItem } from '@framework/cart' + +const AddToCartButton = ({ variantId, quantity }) => { + const addItem = useAddItem() + + const addToCart = async () => { + await addItem({ + variantId, + }) + } + + return <button onClick={addToCart}>Add To Cart</button> +} +``` + +### useRemoveItem + +```js +import { useRemoveItem } from '@framework/cart' + +const RemoveButton = ({ item }) => { + const removeItem = useRemoveItem() + + const handleRemove = async () => { + await removeItem({ id: item.id }) + } + + return <button onClick={handleRemove}>Remove</button> +} +``` + +### useUpdateItem + +```js +import { useUpdateItem } from '@framework/cart' + +const CartItem = ({ item }) => { + const [quantity, setQuantity] = useState(item.quantity) + const updateItem = useUpdateItem(item) + + const updateQuantity = async (e) => { + const val = e.target.value + await updateItem({ quantity: val }) + } + + return ( + <input + type="number" + max={99} + min={0} + value={quantity} + onChange={updateQuantity} + /> + ) +} +``` + +## APIs + +Collections of APIs to fetch data from a Shopify store. + +The data is fetched using the [Shopify JavaScript Buy SDK](https://github.com/Shopify/js-buy-sdk#readme). Read the [Shopify Storefront API reference](https://shopify.dev/docs/storefront-api/reference) for more information. + +### getProduct + +Get a single product by its `handle`. + +```js +import getProduct from '@framework/product/get-product' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const product = await getProduct({ + variables: { slug }, + config, +}) +``` + +### getAllProducts + +```js +import getAllProducts from '@framework/product/get-all-products' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const { products } = await getAllProducts({ + variables: { first: 12 }, + config, +}) +``` + +### getAllCollections + +```js +import getAllCollections from '@framework/product/get-all-collections' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const collections = await getAllCollections({ + config, +}) +``` + +### getAllPages + +```js +import getAllPages from '@framework/common/get-all-pages' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const pages = await getAllPages({ + variables: { first: 12 }, + config, +}) +``` diff --git a/framework/reactioncommerce/api/cart/handlers/add-item.ts b/framework/reactioncommerce/api/cart/handlers/add-item.ts new file mode 100644 index 00000000..8d17b845 --- /dev/null +++ b/framework/reactioncommerce/api/cart/handlers/add-item.ts @@ -0,0 +1,145 @@ +import type { CartHandlers } from '..' +import { + addCartItemsMutation, + createCartMutation, +} from '@framework/utils/mutations' +import getCartCookie from '@framework/api/utils/get-cart-cookie' +import reconcileCarts from '@framework/api/utils/reconcile-carts' +import { + REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + REACTION_CART_ID_COOKIE, + REACTION_CUSTOMER_TOKEN_COOKIE, +} from '@framework/const' + +const addItem: CartHandlers['addItem'] = async ({ + req: { cookies }, + res, + body: { item }, + config, +}) => { + console.log('add-item API', item.productId) + console.log('variantId', item.variantId) + + const { + [REACTION_ANONYMOUS_CART_TOKEN_COOKIE]: anonymousCartToken, + [REACTION_CUSTOMER_TOKEN_COOKIE]: reactionCustomerToken, + } = cookies + + let { [REACTION_CART_ID_COOKIE]: cartId } = cookies + + if (!cartId) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Missing cartId cookie' }], + }) + } + + if (!item) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Missing item' }], + }) + } + if (!item.quantity) item.quantity = 1 + + if (cartId === config.dummyEmptyCartId) { + const createdCart = await config.fetch(createCartMutation, { + variables: { + input: { + shopId: config.shopId, + items: [ + { + productConfiguration: { + productId: item.productId, + productVariantId: item.variantId, + }, + quantity: item.quantity, + price: item.pricing, + }, + ], + }, + }, + }) + + console.log('cart token', createdCart.data.createCart.token) + console.log('created cart', createdCart.data.createCart.cart) + + res.setHeader('Set-Cookie', [ + getCartCookie( + config.anonymousCartTokenCookie, + createdCart.data.createCart.token, + 999 + ), + getCartCookie( + config.cartIdCookie, + createdCart.data.createCart.cart._id, + 999 + ), + ]) + + return res.status(200).json(createdCart.data) + } + + const anonymousTokenParam = <any>{} + const authorizationHeaderParam = <any>{} + + if (anonymousCartToken) { + anonymousTokenParam.cartToken = anonymousCartToken + } + + if (reactionCustomerToken) { + authorizationHeaderParam[ + 'Authorization' + ] = `Bearer ${reactionCustomerToken}` + } + + if (anonymousCartToken && reactionCustomerToken) { + console.log('reconciliating carts')( + ({ _id: cartId } = await reconcileCarts({ + config, + cartId, + anonymousCartToken, + reactionCustomerToken, + })) + ) + + // Clear the anonymous cart token cookie and update cart ID cookie + res.setHeader('Set-Cookie', [ + getCartCookie(config.anonymousCartTokenCookie), + getCartCookie(config.cartIdCookie, cartId, 999), + ]) + } + + const updatedCart = await config.fetch( + addCartItemsMutation, + { + variables: { + input: { + cartId, + ...anonymousTokenParam, + items: [ + { + productConfiguration: { + productId: item.productId, + productVariantId: item.variantId, + }, + quantity: item.quantity, + price: item.pricing, + }, + ], + }, + }, + }, + { + headers: { + ...authorizationHeaderParam, + }, + } + ) + + console.log('updatedCart', updatedCart) + + return res.status(200).json(updatedCart.data) +} + +export default addItem diff --git a/framework/reactioncommerce/api/cart/handlers/get-cart.ts b/framework/reactioncommerce/api/cart/handlers/get-cart.ts new file mode 100644 index 00000000..f322bb66 --- /dev/null +++ b/framework/reactioncommerce/api/cart/handlers/get-cart.ts @@ -0,0 +1,94 @@ +import type { CartHandlers } from '../' +import getAnonymousCartQuery from '@framework/utils/queries/get-anonymous-cart' +import accountCartByAccountIdQuery from '@framework/utils/queries/account-cart-by-account-id' +import getCartCookie from '@framework/api/utils/get-cart-cookie' +import reconcileCarts from '@framework/api/utils/reconcile-carts' +import getViewerId from '@framework/customer/get-viewer-id' +import { + REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + REACTION_CART_ID_COOKIE, + REACTION_CUSTOMER_TOKEN_COOKIE, +} from '@framework/const' +import { normalizeCart } from '@framework/utils' + +// Return current cart info +const getCart: CartHandlers['getCart'] = async ({ req, res, config }) => { + const { + cookies: { + [REACTION_ANONYMOUS_CART_TOKEN_COOKIE]: anonymousCartToken, + [REACTION_CART_ID_COOKIE]: cartId, + [REACTION_CUSTOMER_TOKEN_COOKIE]: reactionCustomerToken, + }, + } = req + + let normalizedCart + + if (cartId && anonymousCartToken && reactionCustomerToken) { + const rawReconciledCart = await reconcileCarts({ + config, + cartId, + anonymousCartToken, + reactionCustomerToken, + }) + + normalizedCart = normalizeCart(rawReconciledCart) + + // Clear the anonymous cart token cookie and update cart ID cookie + res.setHeader('Set-Cookie', [ + getCartCookie(config.anonymousCartTokenCookie), + getCartCookie(config.cartIdCookie, normalizedCart.id, 999), + ]) + } else if (cartId && anonymousCartToken) { + const { + data: { cart: rawAnonymousCart }, + } = await config.fetch(getAnonymousCartQuery, { + variables: { + cartId, + cartToken: anonymousCartToken, + }, + }) + + normalizedCart = normalizeCart(rawAnonymousCart) + } else if (reactionCustomerToken && !anonymousCartToken) { + const accountId = await getViewerId({ + customerToken: reactionCustomerToken, + config, + }) + + const { + data: { cart: rawAccountCart }, + } = await config.fetch( + accountCartByAccountIdQuery, + { + variables: { + accountId, + shopId: config.shopId, + }, + }, + { + headers: { + Authorization: `Bearer ${reactionCustomerToken}`, + }, + } + ) + + normalizedCart = normalizeCart(rawAccountCart) + + if (cartId !== normalizedCart.id) { + res.setHeader( + 'Set-Cookie', + getCartCookie(config.cartIdCookie, rawAccountCart._id, 999) + ) + } + } else { + // If there's no cart for now, store a dummy cart ID to keep Next Commerce happy + res.setHeader( + 'Set-Cookie', + getCartCookie(config.cartIdCookie, config.dummyEmptyCartId, 999) + ) + } + + res.status(200).json({ data: normalizedCart ?? null }) +} + +export default getCart diff --git a/framework/reactioncommerce/api/cart/index.ts b/framework/reactioncommerce/api/cart/index.ts new file mode 100644 index 00000000..0e8e0250 --- /dev/null +++ b/framework/reactioncommerce/api/cart/index.ts @@ -0,0 +1,60 @@ +import isAllowedMethod from '../utils/is-allowed-method' +import createApiHandler, { + ReactionCommerceApiHandler, + ReactionCommerceHandler, +} from '../utils/create-api-handler' +import { ReactionCommerceApiError } from '../utils/errors' +import getCart from './handlers/get-cart' +import addItem from './handlers/add-item' +import type { + Cart, + GetCartHandlerBody, + AddCartItemHandlerBody, +} from '../../types' + +export type CartHandlers = { + getCart: ReactionCommerceHandler<Cart, GetCartHandlerBody> + addItem: ReactionCommerceHandler<Cart, AddCartItemHandlerBody> +} + +const METHODS = ['GET', 'POST'] + +// TODO: a complete implementation should have schema validation for `req.body` +const cartApi: ReactionCommerceApiHandler<Cart, CartHandlers> = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + const { cookies } = req + const cartId = cookies[config.anonymousCartTokenCookie] + + try { + // Return current cart info + if (req.method === 'GET') { + const body = { cartId } + return await handlers['getCart']({ req, res, config, body }) + } + + // Create or add an item to the cart + if (req.method === 'POST') { + const body = { ...req.body, cartId } + return await handlers['addItem']({ req, res, config, body }) + } + } catch (error) { + console.error(error) + + const message = + error instanceof ReactionCommerceApiError + ? 'An unexpected error occurred with the Reaction Commerce API' + : 'An unexpected error occurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +export const handlers = { getCart, addItem } + +export default createApiHandler(cartApi, handlers, {}) diff --git a/framework/reactioncommerce/api/catalog/index.ts b/framework/reactioncommerce/api/catalog/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/reactioncommerce/api/catalog/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/reactioncommerce/api/catalog/products.ts b/framework/reactioncommerce/api/catalog/products.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/reactioncommerce/api/catalog/products.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/reactioncommerce/api/checkout/index.ts b/framework/reactioncommerce/api/checkout/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/reactioncommerce/api/checkout/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/reactioncommerce/api/customer.ts b/framework/reactioncommerce/api/customer.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/reactioncommerce/api/customer.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/reactioncommerce/api/customers/index.ts b/framework/reactioncommerce/api/customers/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/reactioncommerce/api/customers/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/reactioncommerce/api/customers/login.ts b/framework/reactioncommerce/api/customers/login.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/reactioncommerce/api/customers/login.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/reactioncommerce/api/customers/logout.ts b/framework/reactioncommerce/api/customers/logout.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/reactioncommerce/api/customers/logout.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/reactioncommerce/api/customers/signup.ts b/framework/reactioncommerce/api/customers/signup.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/reactioncommerce/api/customers/signup.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/reactioncommerce/api/index.ts b/framework/reactioncommerce/api/index.ts new file mode 100644 index 00000000..0ec59fe6 --- /dev/null +++ b/framework/reactioncommerce/api/index.ts @@ -0,0 +1,69 @@ +import type { CommerceAPIConfig } from '@commerce/api' + +import { + API_URL, + REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + REACTION_CART_ID_COOKIE, + REACTION_EMPTY_DUMMY_CART_ID, + REACTION_CUSTOMER_TOKEN_COOKIE, + REACTION_COOKIE_EXPIRE, + SHOP_ID, +} from '../const' + +if (!API_URL) { + throw new Error( + `The environment variable API_URL is missing and it's required to access your store` + ) +} + +import fetchGraphqlApi from './utils/fetch-graphql-api' + +export interface ReactionCommerceConfig + extends Omit<CommerceAPIConfig, 'apiToken'> { + shopId: string + cartIdCookie: string + dummyEmptyCartId?: string + anonymousCartTokenCookie?: string + anonymousCartTokenCookieMaxAge?: number +} + +export class Config { + private config: ReactionCommerceConfig + + constructor(config: ReactionCommerceConfig) { + this.config = config + } + + getConfig(userConfig: Partial<ReactionCommerceConfig> = {}) { + return Object.entries(userConfig).reduce<ReactionCommerceConfig>( + (cfg, [key, value]) => Object.assign(cfg, { [key]: value }), + { ...this.config } + ) + } + + setConfig(newConfig: Partial<ReactionCommerceConfig>) { + Object.assign(this.config, newConfig) + } +} + +const config = new Config({ + locale: 'en-US', + commerceUrl: API_URL, + cartCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + cartIdCookie: REACTION_CART_ID_COOKIE, + dummyEmptyCartId: REACTION_EMPTY_DUMMY_CART_ID, + cartCookieMaxAge: REACTION_COOKIE_EXPIRE, + anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + anonymousCartTokenCookieMaxAge: REACTION_COOKIE_EXPIRE, + fetch: fetchGraphqlApi, + customerCookie: REACTION_CUSTOMER_TOKEN_COOKIE, + shopId: SHOP_ID, +}) + +export function getConfig(userConfig?: Partial<ReactionCommerceConfig>) { + return config.getConfig(userConfig) +} + +export function setConfig(newConfig: Partial<ReactionCommerceConfig>) { + return config.setConfig(newConfig) +} diff --git a/framework/reactioncommerce/api/operations/get-page.ts b/framework/reactioncommerce/api/operations/get-page.ts new file mode 100644 index 00000000..7fd1ddb7 --- /dev/null +++ b/framework/reactioncommerce/api/operations/get-page.ts @@ -0,0 +1,25 @@ +import { Page } from '../../schema' +import { ReactionCommerceConfig, getConfig } from '..' + +export type GetPageResult<T extends { page?: any } = { page?: Page }> = T + +export type PageVariables = { + id: string +} + +async function getPage({ + url, + variables, + config, + preview, +}: { + url?: string + variables: PageVariables + config?: ReactionCommerceConfig + preview?: boolean +}): Promise<GetPageResult> { + config = getConfig(config) + return {} +} + +export default getPage diff --git a/framework/reactioncommerce/api/utils/create-api-handler.ts b/framework/reactioncommerce/api/utils/create-api-handler.ts new file mode 100644 index 00000000..b01e0466 --- /dev/null +++ b/framework/reactioncommerce/api/utils/create-api-handler.ts @@ -0,0 +1,58 @@ +import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next' +import { ReactionCommerceConfig, getConfig } from '..' + +export type ReactionCommerceApiHandler< + T = any, + H extends ReactionCommerceHandlers = {}, + Options extends {} = {} +> = ( + req: NextApiRequest, + res: NextApiResponse<ReactionCommerceApiResponse<T>>, + config: ReactionCommerceConfig, + handlers: H, + // Custom configs that may be used by a particular handler + options: Options +) => void | Promise<void> + +export type ReactionCommerceHandler<T = any, Body = null> = (options: { + req: NextApiRequest + res: NextApiResponse<ReactionCommerceApiResponse<T>> + config: ReactionCommerceConfig + body: Body +}) => void | Promise<void> + +export type ReactionCommerceHandlers<T = any> = { + [k: string]: ReactionCommerceHandler<T, any> +} + +export type ReactionCommerceApiResponse<T> = { + data: T | null + errors?: { message: string; code?: string }[] +} + +export default function createApiHandler< + T = any, + H extends ReactionCommerceHandlers = {}, + Options extends {} = {} +>( + handler: ReactionCommerceApiHandler<T, H, Options>, + handlers: H, + defaultOptions: Options +) { + return function getApiHandler({ + config, + operations, + options, + }: { + config?: ReactionCommerceConfig + operations?: Partial<H> + options?: Options extends {} ? Partial<Options> : never + } = {}): NextApiHandler { + const ops = { ...operations, ...handlers } + const opts = { ...defaultOptions, ...options } + + return function apiHandler(req, res) { + return handler(req, res, getConfig(config), ops, opts) + } + } +} diff --git a/framework/reactioncommerce/api/utils/errors.ts b/framework/reactioncommerce/api/utils/errors.ts new file mode 100644 index 00000000..5b4296ac --- /dev/null +++ b/framework/reactioncommerce/api/utils/errors.ts @@ -0,0 +1,25 @@ +import type { Response } from '@vercel/fetch' + +// Used for GraphQL errors +export class ReactionCommerceGraphQLError extends Error {} + +export class ReactionCommerceApiError extends Error { + status: number + res: Response + data: any + + constructor(msg: string, res: Response, data?: any) { + super(msg) + this.name = 'ReactionCommerceApiError' + this.status = res.status + this.res = res + this.data = data + } +} + +export class ReactionCommerceNetworkError extends Error { + constructor(msg: string) { + super(msg) + this.name = 'ReactionCommerceNetworkError' + } +} diff --git a/framework/reactioncommerce/api/utils/fetch-all-products.ts b/framework/reactioncommerce/api/utils/fetch-all-products.ts new file mode 100644 index 00000000..94f5c721 --- /dev/null +++ b/framework/reactioncommerce/api/utils/fetch-all-products.ts @@ -0,0 +1,41 @@ +import { ProductEdge } from '../../schema' +import { ReactionCommerceConfig } from '..' + +const fetchAllProducts = async ({ + config, + query, + variables, + acc = [], + cursor, +}: { + config: ReactionCommerceConfig + query: string + acc?: ProductEdge[] + variables?: any + cursor?: string +}): Promise<ProductEdge[]> => { + const { data } = await config.fetch(query, { + variables: { ...variables, cursor }, + }) + + const edges: ProductEdge[] = data.products?.edges ?? [] + const hasNextPage = data.products?.pageInfo?.hasNextPage + acc = acc.concat(edges) + + if (hasNextPage) { + const cursor = edges.pop()?.cursor + if (cursor) { + return fetchAllProducts({ + config, + query, + variables, + acc, + cursor, + }) + } + } + + return acc +} + +export default fetchAllProducts diff --git a/framework/reactioncommerce/api/utils/fetch-graphql-api.ts b/framework/reactioncommerce/api/utils/fetch-graphql-api.ts new file mode 100644 index 00000000..6de00990 --- /dev/null +++ b/framework/reactioncommerce/api/utils/fetch-graphql-api.ts @@ -0,0 +1,32 @@ +import type { GraphQLFetcher } from '@commerce/api' +import fetch from './fetch' +import { API_URL } from '../../const' +import { getError } from '../../utils/handle-fetch-response' + +const fetchGraphqlApi: GraphQLFetcher = async ( + query: string, + { variables } = {}, + fetchOptions +) => { + const res = await fetch(API_URL, { + ...fetchOptions, + method: 'POST', + headers: { + ...fetchOptions?.headers, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query, + variables, + }), + }) + + const { data, errors, status } = await res.json() + + if (errors) { + throw getError(errors, status) + } + + return { data, res } +} +export default fetchGraphqlApi diff --git a/framework/reactioncommerce/api/utils/fetch.ts b/framework/reactioncommerce/api/utils/fetch.ts new file mode 100644 index 00000000..0b836710 --- /dev/null +++ b/framework/reactioncommerce/api/utils/fetch.ts @@ -0,0 +1,2 @@ +import zeitFetch from '@vercel/fetch' +export default zeitFetch() diff --git a/framework/reactioncommerce/api/utils/get-cart-cookie.ts b/framework/reactioncommerce/api/utils/get-cart-cookie.ts new file mode 100644 index 00000000..7ca6cd5e --- /dev/null +++ b/framework/reactioncommerce/api/utils/get-cart-cookie.ts @@ -0,0 +1,20 @@ +import { serialize, CookieSerializeOptions } from 'cookie' + +export default function getCartCookie( + name: string, + cartId?: string, + maxAge?: number +) { + const options: CookieSerializeOptions = + cartId && maxAge + ? { + maxAge, + expires: new Date(Date.now() + maxAge * 1000), + secure: process.env.NODE_ENV === 'production', + path: '/', + sameSite: 'lax', + } + : { maxAge: -1, path: '/' } // Removes the cookie + + return serialize(name, cartId || '', options) +} diff --git a/framework/reactioncommerce/api/utils/is-allowed-method.ts b/framework/reactioncommerce/api/utils/is-allowed-method.ts new file mode 100644 index 00000000..78bbba56 --- /dev/null +++ b/framework/reactioncommerce/api/utils/is-allowed-method.ts @@ -0,0 +1,28 @@ +import type { NextApiRequest, NextApiResponse } from 'next' + +export default function isAllowedMethod( + req: NextApiRequest, + res: NextApiResponse, + allowedMethods: string[] +) { + const methods = allowedMethods.includes('OPTIONS') + ? allowedMethods + : [...allowedMethods, 'OPTIONS'] + + if (!req.method || !methods.includes(req.method)) { + res.status(405) + res.setHeader('Allow', methods.join(', ')) + res.end() + return false + } + + if (req.method === 'OPTIONS') { + res.status(200) + res.setHeader('Allow', methods.join(', ')) + res.setHeader('Content-Length', '0') + res.end() + return false + } + + return true +} diff --git a/framework/reactioncommerce/api/utils/reconcile-carts.ts b/framework/reactioncommerce/api/utils/reconcile-carts.ts new file mode 100644 index 00000000..6bebd686 --- /dev/null +++ b/framework/reactioncommerce/api/utils/reconcile-carts.ts @@ -0,0 +1,34 @@ +import reconcileCartsMutation from '@framework/utils/mutations/reconcile-carts' + +async function reconcileCarts({ + config, + cartId, + anonymousCartToken, + reactionCustomerToken, +}) { + const { + data: { + reconcileCarts: { cart: rawReconciledCart }, + }, + } = await config.fetch( + reconcileCartsMutation, + { + variables: { + input: { + anonymousCartId: cartId, + cartToken: anonymousCartToken, + shopId: config.shopId, + }, + }, + }, + { + headers: { + Authorization: `Bearer ${reactionCustomerToken}`, + }, + } + ) + + return rawReconciledCart +} + +export default reconcileCarts diff --git a/framework/reactioncommerce/auth/index.ts b/framework/reactioncommerce/auth/index.ts new file mode 100644 index 00000000..36e757a8 --- /dev/null +++ b/framework/reactioncommerce/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/framework/reactioncommerce/auth/use-login.tsx b/framework/reactioncommerce/auth/use-login.tsx new file mode 100644 index 00000000..a479d929 --- /dev/null +++ b/framework/reactioncommerce/auth/use-login.tsx @@ -0,0 +1,70 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useCustomer from '../customer/use-customer' +import authenticateMutation from '../utils/mutations/authenticate' +import { + CustomerAccessTokenCreateInput, + CustomerUserError, + Mutation, + MutationAuthenticateArgs, +} from '../schema' +import useLogin, { UseLogin } from '@commerce/auth/use-login' +import { setCustomerToken } from '../utils' + +export default useLogin as UseLogin<typeof handler> + +const getErrorMessage = ({ code, message }: CustomerUserError) => { + switch (code) { + case 'UNIDENTIFIED_CUSTOMER': + message = 'Cannot find an account that matches the provided credentials' + break + } + return message +} + +export const handler: MutationHook<null, {}, CustomerAccessTokenCreateInput> = { + fetchOptions: { + query: authenticateMutation, + }, + async fetcher({ input: { email, password }, options, fetch }) { + if (!(email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to login', + }) + } + + console.log('querying API') + + const { authenticate } = await fetch<Mutation, MutationAuthenticateArgs>({ + ...options, + variables: { + serviceName: 'password', + params: { user: { email }, password }, + }, + }) + + const accessToken = authenticate?.tokens?.accessToken + + console.log('accessToken', accessToken) + + if (accessToken) { + setCustomerToken(accessToken) + } + + return null + }, + useHook: ({ fetch }) => () => { + const { revalidate } = useCustomer() + + return useCallback( + async function login(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/reactioncommerce/auth/use-logout.tsx b/framework/reactioncommerce/auth/use-logout.tsx new file mode 100644 index 00000000..a4ea1d3d --- /dev/null +++ b/framework/reactioncommerce/auth/use-logout.tsx @@ -0,0 +1,33 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import useLogout, { UseLogout } from '@commerce/auth/use-logout' +import useCustomer from '../customer/use-customer' +import logoutMutation from '../utils/mutations/logout' +import { getCustomerToken, setCustomerToken } from '../utils/customer-token' + +export default useLogout as UseLogout<typeof handler> + +export const handler: MutationHook<null> = { + fetchOptions: { + query: logoutMutation, + }, + async fetcher({ options, fetch }) { + await fetch({ + ...options, + }) + setCustomerToken(null) + return null + }, + useHook: ({ fetch }) => () => { + const { mutate } = useCustomer() + + return useCallback( + async function logout() { + const data = await fetch() + await mutate(null, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/reactioncommerce/auth/use-signup.tsx b/framework/reactioncommerce/auth/use-signup.tsx new file mode 100644 index 00000000..72ee6076 --- /dev/null +++ b/framework/reactioncommerce/auth/use-signup.tsx @@ -0,0 +1,57 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useSignup, { UseSignup } from '@commerce/auth/use-signup' +import { setCustomerToken } from '@framework/utils' +import { createUserMutation } from '@framework/utils/mutations' +import useCustomer from '../customer/use-customer' +import { CreateUserInput } from '../schema' + +export default useSignup as UseSignup<typeof handler> + +export const handler: MutationHook< + null, + {}, + CreateUserInput, + CreateUserInput +> = { + fetchOptions: { + query: createUserMutation, + }, + async fetcher({ input: { email, password }, options, fetch }) { + if (!(email && password)) { + throw new CommerceError({ + message: 'An email and password are required to sign up', + }) + } + const { createUser } = await fetch({ + ...options, + variables: { + input: { + email, + password, + }, + }, + }) + + const accessToken = createUser?.loginResult?.tokens?.accessToken + + if (accessToken) { + setCustomerToken(accessToken) + } + + return createUser + }, + useHook: ({ fetch }) => () => { + const { revalidate } = useCustomer() + + return useCallback( + async function signup(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/reactioncommerce/cart/index.ts b/framework/reactioncommerce/cart/index.ts new file mode 100644 index 00000000..3d288b1d --- /dev/null +++ b/framework/reactioncommerce/cart/index.ts @@ -0,0 +1,3 @@ +export { default as useCart } from './use-cart' +export { default as useAddItem } from './use-add-item' +export { default as useRemoveItem } from './use-remove-item' diff --git a/framework/reactioncommerce/cart/use-add-item.tsx b/framework/reactioncommerce/cart/use-add-item.tsx new file mode 100644 index 00000000..228d99bb --- /dev/null +++ b/framework/reactioncommerce/cart/use-add-item.tsx @@ -0,0 +1,46 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' +import type { Cart, CartItemBody, AddCartItemBody } from '../types' +import useCart from './use-cart' + +export default useAddItem as UseAddItem<typeof handler> + +export const handler: MutationHook<Cart, {}, CartItemBody> = { + fetchOptions: { + url: '/api/reactioncommerce/cart', + method: 'POST', + }, + async fetcher({ input: item, options, fetch }) { + console.log('add cart item', item) + + if ( + item.quantity && + (!Number.isInteger(item.quantity) || item.quantity! < 1) + ) { + throw new CommerceError({ + message: 'The item quantity has to be a valid integer greater than 0', + }) + } + + const data = await fetch<Cart, AddCartItemBody>({ + ...options, + body: { item }, + }) + + return data + }, + useHook: ({ fetch }) => () => { + const { mutate } = useCart() + + return useCallback( + async function addItem(input) { + const data = await fetch({ input }) + await mutate(data, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/reactioncommerce/cart/use-cart.tsx b/framework/reactioncommerce/cart/use-cart.tsx new file mode 100644 index 00000000..b2bb66fe --- /dev/null +++ b/framework/reactioncommerce/cart/use-cart.tsx @@ -0,0 +1,41 @@ +import { useMemo } from 'react' +import { SWRHook } from '@commerce/utils/types' +import useCart, { UseCart, FetchCartInput } from '@commerce/cart/use-cart' +import type { Cart } from '../types' + +export default useCart as UseCart<typeof handler> + +export const handler: SWRHook< + Cart | null, + {}, + FetchCartInput, + { isEmpty?: boolean } +> = { + fetchOptions: { + method: 'GET', + url: '/api/reactioncommerce/cart', + }, + async fetcher({ input: { cartId }, options, fetch }) { + console.log('cart API fetcher', options) + const data = await fetch(options) + return data + }, + useHook: ({ useData }) => (input) => { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} diff --git a/framework/reactioncommerce/cart/use-remove-item.tsx b/framework/reactioncommerce/cart/use-remove-item.tsx new file mode 100644 index 00000000..a7e06217 --- /dev/null +++ b/framework/reactioncommerce/cart/use-remove-item.tsx @@ -0,0 +1,85 @@ +import { useCallback } from 'react' + +import type { + MutationHookContext, + HookFetcherContext, +} from '@commerce/utils/types' + +import { ValidationError } from '@commerce/utils/errors' + +import useRemoveItem, { + RemoveItemInput as RemoveItemInputBase, + UseRemoveItem, +} from '@commerce/cart/use-remove-item' + +import useCart from './use-cart' +import { + removeCartItemsMutation, + getAnonymousCartToken, + getAnonymousCartId, + normalizeCart, +} from '../utils' +import { Cart, LineItem } from '../types' +import { Mutation, MutationUpdateCartItemsQuantityArgs } from '../schema' +import { RemoveCartItemBody } from '@commerce/types' + +export type RemoveItemFn<T = any> = T extends LineItem + ? (input?: RemoveItemInput<T>) => Promise<Cart | null> + : (input: RemoveItemInput<T>) => Promise<Cart | null> + +export type RemoveItemInput<T = any> = T extends LineItem + ? Partial<RemoveItemInputBase> + : RemoveItemInputBase + +export default useRemoveItem as UseRemoveItem<typeof handler> + +export const handler = { + fetchOptions: { + query: removeCartItemsMutation, + }, + async fetcher({ + input: { itemId }, + options, + fetch, + }: HookFetcherContext<RemoveCartItemBody>) { + const { removeCartItems } = await fetch< + Mutation, + MutationUpdateCartItemsQuantityArgs + >({ + ...options, + variables: { + input: { + cartId: getAnonymousCartId(), + cartToken: getAnonymousCartToken(), + cartItemIds: [itemId], + }, + }, + }) + return normalizeCart(removeCartItems?.cart) + }, + useHook: ({ + fetch, + }: MutationHookContext<Cart | null, RemoveCartItemBody>) => < + T extends LineItem | undefined = undefined + >( + ctx: { item?: T } = {} + ) => { + const { item } = ctx + const { mutate } = useCart() + const removeItem: RemoveItemFn<LineItem> = async (input) => { + const itemId = input?.id ?? item?.id + + if (!itemId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ input: { itemId } }) + await mutate(data, false) + return data + } + + return useCallback(removeItem as RemoveItemFn<T>, [fetch, mutate]) + }, +} diff --git a/framework/reactioncommerce/cart/use-update-item.tsx b/framework/reactioncommerce/cart/use-update-item.tsx new file mode 100644 index 00000000..a84f2fef --- /dev/null +++ b/framework/reactioncommerce/cart/use-update-item.tsx @@ -0,0 +1,116 @@ +import { useCallback } from 'react' +import debounce from 'lodash.debounce' +import type { + HookFetcherContext, + MutationHookContext, +} from '@commerce/utils/types' +import { ValidationError } from '@commerce/utils/errors' +import useUpdateItem, { + UpdateItemInput as UpdateItemInputBase, + UseUpdateItem, +} from '@commerce/cart/use-update-item' + +import useCart from './use-cart' +import { handler as removeItemHandler } from './use-remove-item' +import type { Cart, LineItem, UpdateCartItemBody } from '../types' +import { + getAnonymousCartToken, + getAnonymousCartId, + updateCartItemsQuantityMutation, + normalizeCart, +} from '../utils' +import { Mutation, MutationUpdateCartItemsQuantityArgs } from '../schema' + +export type UpdateItemInput<T = any> = T extends LineItem + ? Partial<UpdateItemInputBase<LineItem>> + : UpdateItemInputBase<LineItem> + +export default useUpdateItem as UseUpdateItem<typeof handler> + +export const handler = { + fetchOptions: { + query: updateCartItemsQuantityMutation, + }, + async fetcher({ + input: { itemId, item }, + options, + fetch, + }: HookFetcherContext<UpdateCartItemBody>) { + if (Number.isInteger(item.quantity)) { + // Also allow the update hook to remove an item if the quantity is lower than 1 + if (item.quantity! < 1) { + return removeItemHandler.fetcher({ + options: removeItemHandler.fetchOptions, + input: { + itemId, + }, + fetch, + }) + } + } else if (item.quantity) { + throw new ValidationError({ + message: 'The item quantity has to be a valid integer', + }) + } + const { updateCartItemsQuantity } = await fetch< + Mutation, + MutationUpdateCartItemsQuantityArgs + >({ + ...options, + variables: { + updateCartItemsQuantityInput: { + cartId: getAnonymousCartId(), + cartToken: getAnonymousCartToken(), + items: [ + { + cartItemId: itemId, + quantity: item.quantity, + }, + ], + }, + }, + }) + + return normalizeCart(updateCartItemsQuantity?.cart) + }, + useHook: ({ + fetch, + }: MutationHookContext<Cart | null, UpdateCartItemBody>) => < + T extends LineItem | undefined = undefined + >( + ctx: { + item?: T + wait?: number + } = {} + ) => { + const { item } = ctx + const { mutate } = useCart() as any + + return useCallback( + debounce(async (input: UpdateItemInput<T>) => { + const itemId = input.id ?? item?.id + const productId = input.productId ?? item?.productId + const variantId = input.productId ?? item?.variantId + if (!itemId || !productId || !variantId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ + input: { + item: { + productId, + variantId, + quantity: input.quantity, + }, + itemId, + }, + }) + await mutate(data, false) + return data + }, ctx.wait ?? 500), + [fetch, mutate] + ) + }, +} diff --git a/framework/reactioncommerce/cart/utils/create-cart.ts b/framework/reactioncommerce/cart/utils/create-cart.ts new file mode 100644 index 00000000..57c95789 --- /dev/null +++ b/framework/reactioncommerce/cart/utils/create-cart.ts @@ -0,0 +1,31 @@ +import { + REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + REACTION_COOKIE_EXPIRE, +} from '../../const' +import createCartMutation from '../../utils/mutations/create-cart' +import Cookies from 'js-cookie' + +export const createCart = async (fetch: any) => { + const data = await fetch({ + query: createCartMutation, + variables: { + input: { + shopId, + }, + }, + }) + + const checkout = data.checkoutCreate?.checkout + const checkoutId = checkout?.id + + if (checkoutId) { + const options = { + expires: REACTION_COOKIE_EXPIRE, + } + Cookies.set(REACTION_ANONYMOUS_CART_TOKEN_COOKIE, checkoutId, options) + } + + return checkout +} + +export default createCart diff --git a/framework/reactioncommerce/cart/utils/fetcher.ts b/framework/reactioncommerce/cart/utils/fetcher.ts new file mode 100644 index 00000000..6afb55f1 --- /dev/null +++ b/framework/reactioncommerce/cart/utils/fetcher.ts @@ -0,0 +1,31 @@ +import { HookFetcherFn } from '@commerce/utils/types' +import { Cart } from '@commerce/types' +import { checkoutCreate, checkoutToCart } from '.' +import { FetchCartInput } from '@commerce/cart/use-cart' + +const fetcher: HookFetcherFn<Cart | null, FetchCartInput> = async ({ + options, + input: { cartId: checkoutId }, + fetch, +}) => { + let checkout + + if (checkoutId) { + const data = await fetch({ + ...options, + variables: { + checkoutId, + }, + }) + checkout = data.node + } + + if (checkout?.completedAt || !checkoutId) { + checkout = await checkoutCreate(fetch) + } + + // TODO: Fix this type + return checkoutToCart({ checkout } as any) +} + +export default fetcher diff --git a/framework/reactioncommerce/cart/utils/index.ts b/framework/reactioncommerce/cart/utils/index.ts new file mode 100644 index 00000000..08ce71ec --- /dev/null +++ b/framework/reactioncommerce/cart/utils/index.ts @@ -0,0 +1,2 @@ +export { default as checkoutToCart } from './checkout-to-cart' +export { default as checkoutCreate } from './create-cart' diff --git a/framework/reactioncommerce/codegen.json b/framework/reactioncommerce/codegen.json new file mode 100644 index 00000000..5679e67f --- /dev/null +++ b/framework/reactioncommerce/codegen.json @@ -0,0 +1,21 @@ +{ + "schema": { + "http://localhost:3000/graphql": { + "headers": {} + } + }, + "generates": { + "./framework/reactioncommerce/schema.d.ts": { + "plugins": ["typescript", "typescript-operations"], + "config": { + "avoidOptionals": true + } + }, + "./framework/reactioncommerce/schema.graphql": { + "plugins": ["schema-ast"] + } + }, + "hooks": { + "afterAllFileWrite": ["prettier --write"] + } +} diff --git a/framework/reactioncommerce/commerce.config.json b/framework/reactioncommerce/commerce.config.json new file mode 100644 index 00000000..ce78b1b1 --- /dev/null +++ b/framework/reactioncommerce/commerce.config.json @@ -0,0 +1,7 @@ +{ + "provider": "reactioncommerce", + "features": { + "wishlist": false, + "customCheckout": true + } +} diff --git a/framework/reactioncommerce/common/get-all-pages.ts b/framework/reactioncommerce/common/get-all-pages.ts new file mode 100644 index 00000000..b7495c7a --- /dev/null +++ b/framework/reactioncommerce/common/get-all-pages.ts @@ -0,0 +1,54 @@ +import { getConfig, ReactionCommerceConfig } from '../api' +import { NavigationTreeItem } from '../schema' +import { getAllPagesQuery } from '../utils/queries' + +type Variables = { + first?: number +} + +type ReturnType = { + pages: Page[] +} + +export type Page = { + id: string + name: string + url: string + sort_order?: number + body: string +} + +const getAllPages = async (options?: { + variables?: Variables + config: ReactionCommerceConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables } = options ?? {} + config = getConfig(config) + const { locale } = config + console.log('locale', locale) + const { data } = await config.fetch(getAllPagesQuery, { + variables: { + ...variables, + shopId: config.shopId, + }, + }) + + const pages = data.shop?.defaultNavigationTree?.items?.map( + ({ + navigationItem: { + _id: id, + data: { contentForLanguage: name, url }, + }, + }: NavigationTreeItem) => ({ + id, + url, + name, + body: '', + }) + ) + + return { pages } +} + +export default getAllPages diff --git a/framework/reactioncommerce/common/get-page.ts b/framework/reactioncommerce/common/get-page.ts new file mode 100644 index 00000000..5f63191b --- /dev/null +++ b/framework/reactioncommerce/common/get-page.ts @@ -0,0 +1,37 @@ +import { getConfig, ReactionCommerceConfig } from '../api' +import getPageQuery from '../utils/queries/get-page-query' +import { Page } from './get-all-pages' + +type Variables = { + id: string +} + +export type GetPageResult<T extends { page?: any } = { page?: Page }> = T + +const getPage = async (options: { + variables: Variables + config: ReactionCommerceConfig + preview?: boolean +}): Promise<GetPageResult> => { + let { config, variables } = options ?? {} + + config = getConfig(config) + const { locale } = config + + const { data } = await config.fetch(getPageQuery, { + variables, + }) + const page = data.node + + return { + page: page + ? { + ...page, + name: page.title, + url: `/${locale}/${page.handle}`, + } + : null, + } +} + +export default getPage diff --git a/framework/reactioncommerce/common/get-site-info.ts b/framework/reactioncommerce/common/get-site-info.ts new file mode 100644 index 00000000..4fcf8868 --- /dev/null +++ b/framework/reactioncommerce/common/get-site-info.ts @@ -0,0 +1,31 @@ +import getCategories, { Category } from '../utils/get-categories' +import getVendors, { Brands } from '../utils/get-vendors' + +import { getConfig, ReactionCommerceConfig } from '../api' + +export type GetSiteInfoResult< + T extends { categories: any[]; brands: any[] } = { + categories: Category[] + brands: Brands + } +> = T + +const getSiteInfo = async (options?: { + variables?: any + config: ReactionCommerceConfig + preview?: boolean +}): Promise<GetSiteInfoResult> => { + let { config } = options ?? {} + + config = getConfig(config) + + const categories = await getCategories(config) + const brands = await getVendors(config) + + return { + categories, + brands, + } +} + +export default getSiteInfo diff --git a/framework/reactioncommerce/const.ts b/framework/reactioncommerce/const.ts new file mode 100644 index 00000000..93032d37 --- /dev/null +++ b/framework/reactioncommerce/const.ts @@ -0,0 +1,14 @@ +export const REACTION_ANONYMOUS_CART_TOKEN_COOKIE = + 'reaction_anonymousCartToken' + +export const REACTION_CUSTOMER_TOKEN_COOKIE = 'reaction_customerToken' + +export const REACTION_CART_ID_COOKIE = 'reaction_cartId' + +export const REACTION_EMPTY_DUMMY_CART_ID = 'DUMMY_EMPTY_CART_ID' + +export const REACTION_COOKIE_EXPIRE = 30 + +export const API_URL = `http://${process.env.REACTION_API_DOMAIN}/graphql` + +export const SHOP_ID = process.env.REACTION_SHOP_ID ?? '' diff --git a/framework/reactioncommerce/customer/get-viewer-id.ts b/framework/reactioncommerce/customer/get-viewer-id.ts new file mode 100644 index 00000000..5e3a5fab --- /dev/null +++ b/framework/reactioncommerce/customer/get-viewer-id.ts @@ -0,0 +1,26 @@ +import { getConfig, ReactionCommerceConfig } from '../api' +import getViewerIdQuery from '../utils/queries/get-viewer-id-query' + +async function getViewerId({ + customerToken: customerAccessToken, + config, +}: { + customerToken: string + config?: ReactionCommerceConfig +}): Promise<number | undefined> { + config = getConfig(config) + + const { data } = await config.fetch( + getViewerIdQuery, + {}, + { + headers: { + Authorization: `Bearer ${customerAccessToken}`, + }, + } + ) + + return data.viewer?._id +} + +export default getViewerId diff --git a/framework/reactioncommerce/customer/index.ts b/framework/reactioncommerce/customer/index.ts new file mode 100644 index 00000000..6c903ecc --- /dev/null +++ b/framework/reactioncommerce/customer/index.ts @@ -0,0 +1 @@ +export { default as useCustomer } from './use-customer' diff --git a/framework/reactioncommerce/customer/use-customer.tsx b/framework/reactioncommerce/customer/use-customer.tsx new file mode 100644 index 00000000..d7cfd467 --- /dev/null +++ b/framework/reactioncommerce/customer/use-customer.tsx @@ -0,0 +1,26 @@ +import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' +import { Customer } from '@commerce/types' +import { SWRHook } from '@commerce/utils/types' +import { viewerQuery, normalizeCustomer } from '../utils' + +export default useCustomer as UseCustomer<typeof handler> + +export const handler: SWRHook<Customer | null> = { + fetchOptions: { + query: viewerQuery, + }, + async fetcher({ options, fetch }) { + const data = await fetch<any | null>({ + ...options, + }) + return normalizeCustomer(data.viewer) ?? null + }, + useHook: ({ useData }) => (input) => { + return useData({ + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions, + }, + }) + }, +} diff --git a/framework/reactioncommerce/fetcher.ts b/framework/reactioncommerce/fetcher.ts new file mode 100644 index 00000000..0ea43543 --- /dev/null +++ b/framework/reactioncommerce/fetcher.ts @@ -0,0 +1,66 @@ +import { FetcherError } from '@commerce/utils/errors' +import type { Fetcher } from '@commerce/utils/types' +import { handleFetchResponse } from './utils' +import { API_URL } from './const' +import { getCustomerToken } from './utils' + +async function getText(res: Response) { + try { + return (await res.text()) || res.statusText + } catch (error) { + return res.statusText + } +} + +async function getError(res: Response) { + if (res.headers.get('Content-Type')?.includes('application/json')) { + const data = await res.json() + return new FetcherError({ errors: data.errors, status: res.status }) + } + return new FetcherError({ message: await getText(res), status: res.status }) +} + +const fetcher: Fetcher = async ({ + url, + method = 'GET', + variables, + body: bodyObj, + query, +}) => { + // if no URL is passed but we have a `query` param, we assume it's GraphQL + if (!url && query) { + const customerToken = getCustomerToken() + const authorizationHeader = {} + + if (customerToken) { + authorizationHeader['Authorization'] = `Bearer ${customerToken}` + } + + return handleFetchResponse( + await fetch(API_URL, { + method: 'POST', + body: JSON.stringify({ query, variables }), + headers: { + 'Content-Type': 'application/json', + ...authorizationHeader, + }, + }) + ) + } + + const hasBody = Boolean(variables || bodyObj) && method !== 'GET' + const body = hasBody + ? JSON.stringify(variables ? { variables } : bodyObj) + : undefined + const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined + const res = await fetch(url!, { method, body, headers }) + + if (res.ok) { + const { data } = await res.json() + return data + } + + throw await getError(res) +} + +export default fetcher diff --git a/framework/reactioncommerce/index.tsx b/framework/reactioncommerce/index.tsx new file mode 100644 index 00000000..e90571c2 --- /dev/null +++ b/framework/reactioncommerce/index.tsx @@ -0,0 +1,54 @@ +import * as React from 'react' +import { ReactNode } from 'react' + +import { + CommerceConfig, + CommerceProvider as CoreCommerceProvider, + useCommerce as useCoreCommerce, +} from '@commerce' + +import { reactionCommerceProvider, ReactionCommerceProvider } from './provider' +import { + REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + SHOP_ID, + REACTION_CART_ID_COOKIE, +} from './const' + +export { reactionCommerceProvider } +export type { ReactionCommerceProvider } + +type ReactionConfig = CommerceConfig & { + shopId: string + anonymousCartTokenCookie: string +} + +export const reactionCommerceConfig: ReactionConfig = { + locale: 'en-us', + anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + cartCookie: REACTION_CART_ID_COOKIE, + shopId: SHOP_ID, +} + +export type ReactionCommerceConfig = Partial<ReactionConfig> + +export type ReactionCommerceProps = { + children?: ReactNode + locale: string +} & ReactionCommerceConfig + +export function CommerceProvider({ + children, + ...config +}: ReactionCommerceProps) { + return ( + <CoreCommerceProvider + // TODO: Fix this type + provider={reactionCommerceProvider as any} + config={{ ...reactionCommerceConfig, ...config }} + > + {children} + </CoreCommerceProvider> + ) +} + +export const useCommerce = () => useCoreCommerce() diff --git a/framework/reactioncommerce/next.config.js b/framework/reactioncommerce/next.config.js new file mode 100644 index 00000000..ce46b706 --- /dev/null +++ b/framework/reactioncommerce/next.config.js @@ -0,0 +1,8 @@ +const commerce = require('./commerce.config.json') + +module.exports = { + commerce, + images: { + domains: ['localhost'], + }, +} diff --git a/framework/reactioncommerce/product/get-all-collections.ts b/framework/reactioncommerce/product/get-all-collections.ts new file mode 100644 index 00000000..fcddcbcc --- /dev/null +++ b/framework/reactioncommerce/product/get-all-collections.ts @@ -0,0 +1,29 @@ +import { CollectionEdge } from '../schema' +import { getConfig, ReactionCommerceConfig } from '../api' +import getAllCollectionsQuery from '../utils/queries/get-all-collections-query' + +const getAllCollections = async (options?: { + variables?: any + config: ReactionCommerceConfig + preview?: boolean +}) => { + let { config, variables = { first: 250 } } = options ?? {} + config = getConfig(config) + + const { data } = await config.fetch(getAllCollectionsQuery, { variables }) + const edges = data.collections?.edges ?? [] + + const categories = edges.map( + ({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({ + entityId, + name, + path: `/${handle}`, + }) + ) + + return { + categories, + } +} + +export default getAllCollections diff --git a/framework/reactioncommerce/product/get-all-product-paths.ts b/framework/reactioncommerce/product/get-all-product-paths.ts new file mode 100644 index 00000000..0dd3e597 --- /dev/null +++ b/framework/reactioncommerce/product/get-all-product-paths.ts @@ -0,0 +1,51 @@ +import { Product } from '@commerce/types' +import { getConfig, ReactionCommerceConfig } from '../api' +import fetchAllProducts from '../api/utils/fetch-all-products' +import { ProductEdge } from '../schema' +import getAllProductsPathsQuery from '../utils/queries/get-all-products-paths-query' + +type ProductPath = { + path: string +} + +export type ProductPathNode = { + node: ProductPath +} + +type ReturnType = { + products: ProductPathNode[] +} + +const getAllProductPaths = async (options?: { + variables?: any + config?: ReactionCommerceConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables = { first: 250 } } = options ?? {} + config = getConfig(config) + + const products = await fetchAllProducts({ + config, + query: getAllProductsPathsQuery, + variables: { + ...variables, + shopIds: [config.shopId], + }, + }) + + return { + products: products?.map( + ({ + node: { + product: { slug }, + }, + }: CatalogItemEdge) => ({ + node: { + path: `/${slug}`, + }, + }) + ), + } +} + +export default getAllProductPaths diff --git a/framework/reactioncommerce/product/get-all-products.ts b/framework/reactioncommerce/product/get-all-products.ts new file mode 100644 index 00000000..a2cbb187 --- /dev/null +++ b/framework/reactioncommerce/product/get-all-products.ts @@ -0,0 +1,41 @@ +import { GraphQLFetcherResult } from '@commerce/api' +import { getConfig, ReactionCommerceConfig } from '../api' +import { CatalogItemEdge, CatalogItemProduct } from '../schema' +import { catalogItemsQuery, normalizeProduct } from '../utils' +import { Product } from '@commerce/types' + +type Variables = { + first?: number + shopIds?: string[] +} + +type ReturnType = { + products: Product[] +} + +const getAllProducts = async (options: { + variables?: Variables + config?: ReactionCommerceConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables = { first: 250 } } = options ?? {} + config = getConfig(config) + + const { data }: GraphQLFetcherResult = await config.fetch(catalogItemsQuery, { + variables: { + ...variables, + shopIds: [config.shopId], + }, + }) + + const catalogItems = + data.catalogItems?.edges?.map(({ node: itemProduct }: CatalogItemEdge) => + normalizeProduct(itemProduct as CatalogItemProduct) + ) ?? [] + + return { + products: catalogItems, + } +} + +export default getAllProducts diff --git a/framework/reactioncommerce/product/get-product.ts b/framework/reactioncommerce/product/get-product.ts new file mode 100644 index 00000000..b568c254 --- /dev/null +++ b/framework/reactioncommerce/product/get-product.ts @@ -0,0 +1,32 @@ +import { GraphQLFetcherResult } from '@commerce/api' +import { getConfig, ReactionCommerceConfig } from '../api' +import { normalizeProduct, getProductQuery } from '../utils' + +type Variables = { + slug: string +} + +type ReturnType = { + product: any +} + +const getProduct = async (options: { + variables: Variables + config: ReactionCommerceConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables } = options ?? {} + config = getConfig(config) + + const { data }: GraphQLFetcherResult = await config.fetch(getProductQuery, { + variables, + }) + + const { catalogItemProduct: product } = data + + return { + product: product ? normalizeProduct(product) : null, + } +} + +export default getProduct diff --git a/framework/reactioncommerce/product/use-price.tsx b/framework/reactioncommerce/product/use-price.tsx new file mode 100644 index 00000000..0174faf5 --- /dev/null +++ b/framework/reactioncommerce/product/use-price.tsx @@ -0,0 +1,2 @@ +export * from '@commerce/product/use-price' +export { default } from '@commerce/product/use-price' diff --git a/framework/reactioncommerce/product/use-search.tsx b/framework/reactioncommerce/product/use-search.tsx new file mode 100644 index 00000000..61260145 --- /dev/null +++ b/framework/reactioncommerce/product/use-search.tsx @@ -0,0 +1,80 @@ +import { SWRHook } from '@commerce/utils/types' +import useSearch, { UseSearch } from '@commerce/product/use-search' + +import { CatalogItemEdge } from '../schema' +import { + catalogItemsQuery, + getCollectionProductsQuery, + getSearchVariables, + normalizeProduct, +} from '../utils' + +import { Product } from '@commerce/types' + +export default useSearch as UseSearch<typeof handler> + +export type SearchProductsInput = { + search?: string + categoryId?: string + brandId?: string + sort?: string + shopId?: string +} + +export type SearchProductsData = { + products: Product[] + found: boolean +} + +export const handler: SWRHook< + SearchProductsData, + SearchProductsInput, + SearchProductsInput +> = { + fetchOptions: { + query: catalogItemsQuery, + }, + async fetcher({ input, options, fetch }) { + const { brandId, shopId } = input + + const data = await fetch({ + query: options.query, + method: options?.method, + variables: { + ...getSearchVariables(input), + shopIds: [shopId], + }, + }) + + let edges + + edges = data.catalogItems?.edges ?? [] + if (brandId) { + edges = edges.filter( + ({ node: { vendor } }: CatalogItemEdge) => vendor === brandId + ) + } + + return { + products: edges.map(({ node }: CatalogItemEdge) => + normalizeProduct(node) + ), + found: !!edges.length, + } + }, + useHook: ({ useData }) => (input = {}) => { + return useData({ + input: [ + ['search', input.search], + ['categoryId', input.categoryId], + ['brandId', input.brandId], + ['sort', input.sort], + ['shopId', input.shopId], + ], + swrOptions: { + revalidateOnFocus: false, + ...input.swrOptions, + }, + }) + }, +} diff --git a/framework/reactioncommerce/provider.ts b/framework/reactioncommerce/provider.ts new file mode 100644 index 00000000..30d6b7c7 --- /dev/null +++ b/framework/reactioncommerce/provider.ts @@ -0,0 +1,34 @@ +import { + REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + REACTION_CART_ID_COOKIE, +} from './const' + +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' + +import fetcher from './fetcher' + +export const reactionCommerceProvider = { + locale: 'en-us', + anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE, + cartIdCookie: REACTION_CART_ID_COOKIE, + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, + features: { + wishlist: false, + }, +} + +export type ReactionCommerceProvider = typeof reactionCommerceProvider diff --git a/framework/reactioncommerce/schema.d.ts b/framework/reactioncommerce/schema.d.ts new file mode 100644 index 00000000..f313e489 --- /dev/null +++ b/framework/reactioncommerce/schema.d.ts @@ -0,0 +1,7652 @@ +export type Maybe<T> = T | null +export type Exact<T extends { [key: string]: unknown }> = { + [K in keyof T]: T[K] +} +export type MakeOptional<T, K extends keyof T> = Omit<T, K> & + { [SubKey in K]?: Maybe<T[SubKey]> } +export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & + { [SubKey in K]: Maybe<T[SubKey]> } +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string + String: string + Boolean: boolean + Int: number + Float: number + /** + * + * An opaque string that identifies a particular result within a connection, + * allowing you to request a subset of results before or after that result. + * + */ + ConnectionCursor: any + /** + * + * An integer between 1 and 50, inclusive. Values less than 1 become 1 and + * values greater than 50 become 50. + * + */ + ConnectionLimitInt: any + /** A date string, such as 2007-12-03, compliant with the `full-date` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. */ + Date: any + /** A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. */ + DateTime: any + /** A string email address */ + Email: any + /** An object with any fields */ + JSONObject: any +} + +/** Represents a single user account */ +export type Account = Node & { + __typename?: 'Account' + /** The account ID */ + _id: Scalars['ID'] + /** A list of physical or mailing addresses associated with this account */ + addressBook?: Maybe<AddressConnection> + /** A list of shops this user can administer with the admin UI */ + adminUIShops?: Maybe<Array<Maybe<Shop>>> + /** Bio to display on profile */ + bio?: Maybe<Scalars['String']> + /** The date and time at which this account was created */ + createdAt: Scalars['DateTime'] + /** The preferred currency used by this account */ + currency?: Maybe<Currency> + /** A list of email records associated with this account */ + emailRecords?: Maybe<Array<Maybe<EmailRecord>>> + /** The first name of the person this account represents, if known */ + firstName?: Maybe<Scalars['String']> + /** The preferred language used by this account */ + language?: Maybe<Scalars['String']> + /** The last name of the person this account represents, if known */ + lastName?: Maybe<Scalars['String']> + /** Arbitrary additional metadata about this account */ + metafields?: Maybe<Array<Maybe<Metafield>>> + /** The full name of the person this account represents, if known */ + name?: Maybe<Scalars['String']> + /** Some note about this account */ + note?: Maybe<Scalars['String']> + /** URL of picture to display on profile */ + picture?: Maybe<Scalars['String']> + /** An object storing plugin-specific preferences for this account */ + preferences?: Maybe<Scalars['JSONObject']> + /** The primary email address for the account. This matches the address in `emailRecords` where `provides` is `default`. */ + primaryEmailAddress: Scalars['Email'] + /** The date and time at which this account was last updated */ + updatedAt?: Maybe<Scalars['DateTime']> + /** The Identity user ID with which this account is associated */ + userId: Scalars['String'] + /** Username */ + username?: Maybe<Scalars['String']> + /** A paged list of the account groups in which this account is listed */ + groups?: Maybe<GroupConnection> +} + +/** Represents a single user account */ +export type AccountAddressBookArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> +} + +/** Represents a single user account */ +export type AccountGroupsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<GroupSortByField> +} + +/** + * Wraps a list of `Accounts`, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type AccountConnection = { + __typename?: 'AccountConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<AccountEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Account>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is an `Account` object */ +export type AccountEdge = NodeEdge & { + __typename?: 'AccountEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The account */ + node?: Maybe<Account> +} + +/** The fields by which you are allowed to sort any query that returns an `AccountConnection` */ +export enum AccountSortByField { + /** Account ID */ + Id = '_id', + /** Date and time at which this account was created */ + CreatedAt = 'createdAt', + /** Date and time at which this account was last updated */ + UpdatedAt = 'updatedAt', +} + +/** Defines a new Address and the account to which it should be added */ +export type AddAccountAddressBookEntryInput = { + /** The account ID */ + accountId: Scalars['ID'] + /** The address to add */ + address: AddressInput + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** The response from the `addAccountAddressBookEntry` mutation */ +export type AddAccountAddressBookEntryPayload = { + __typename?: 'AddAccountAddressBookEntryPayload' + /** The added address */ + address?: Maybe<Address> + /** The added address edge */ + addressEdge?: Maybe<AddressEdge> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Defines a new Email and the account to which it should be added */ +export type AddAccountEmailRecordInput = { + /** The account ID, which defaults to the viewer account */ + accountId?: Maybe<Scalars['ID']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The email address to add */ + email: Scalars['Email'] +} + +/** The response from the `addAccountEmailRecord` mutation */ +export type AddAccountEmailRecordPayload = { + __typename?: 'AddAccountEmailRecordPayload' + /** The account, with updated `emailRecords` */ + account?: Maybe<Account> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Defines a group and account that should be linked */ +export type AddAccountToGroupInput = { + /** The account ID */ + accountId: Scalars['ID'] + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The group ID */ + groupId: Scalars['ID'] +} + +/** The response from the `addAccountToGroup` mutation */ +export type AddAccountToGroupPayload = { + __typename?: 'AddAccountToGroupPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated group */ + group?: Maybe<Group> +} + +/** Input for the `addCartItems` mutation */ +export type AddCartItemsInput = { + /** The cart ID */ + cartId: Scalars['ID'] + /** If this cart is anonymous, provide the `cartToken` that was returned in the `CreateCartPayload` */ + cartToken?: Maybe<Scalars['String']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Array of items to be added to the cart */ + items: Array<Maybe<CartItemInput>> +} + +/** The payload returned from the `addCartItems` mutation call */ +export type AddCartItemsPayload = { + __typename?: 'AddCartItemsPayload' + /** + * The modified cart. You should check `incorrectPriceFailures` and `minOrderQuantityFailures` for + * information necessary to display errors to the shopper. Some items may not have been added. + */ + cart?: Maybe<Cart> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** + * Clients should check to see if any items failed to be added due to the price not matching the current price. + * In general, a user interface should display the correct current prices to the shopper, confirm that they still + * want to add the items, and then call `createCart` or `addCartItems` to do so. + * + * Note that this field will always exist but may be an empty array if there were no failures of this type. + */ + incorrectPriceFailures: Array<Maybe<IncorrectPriceFailureDetails>> + /** + * Clients should check to see if any items failed to be added due to quantity being below the minimum order + * quantity defined for the product variant. In general, a user interface should display the minimum order + * quantity to the shopper and allow them to add that quantity or greater. + * + * Note that this field will always exist but may be an empty array if there were no failures of this type. + */ + minOrderQuantityFailures: Array<Maybe<MinOrderQuantityFailureDetails>> +} + +/** Input for the addOrderFulfillmentGroup mutation */ +export type AddOrderFulfillmentGroupInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The order fulfillment group input, used to build the new group */ + fulfillmentGroup: OrderFulfillmentGroupExistingOrderInput + /** Optional list of order item IDs that should be moved from an existing group to the new group */ + moveItemIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** ID of the order that has the item you want to add the group to */ + orderId: Scalars['ID'] +} + +/** Response payload for the addOrderFulfillmentGroup mutation */ +export type AddOrderFulfillmentGroupPayload = { + __typename?: 'AddOrderFulfillmentGroupPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of the added fulfillment group */ + newFulfillmentGroupId: Scalars['ID'] + /** The updated order */ + order: Order +} + +/** Input for `addTag` mutation */ +export type AddTagInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Title to display to customers */ + displayTitle?: Maybe<Scalars['String']> + /** Hero media URL */ + heroMediaUrl?: Maybe<Scalars['String']> + /** Whether the tag is visible */ + isVisible: Scalars['Boolean'] + /** Tag metafields */ + metafields?: Maybe<Array<Maybe<MetafieldInput>>> + /** Unique name of the tag */ + name: Scalars['String'] + /** The shop that owns the tag */ + shopId: Scalars['ID'] + /** The tag slug. If left blank, the name will be slugified and saved as the slug */ + slug?: Maybe<Scalars['String']> +} + +/** Response payload for `addTag` mutation */ +export type AddTagPayload = { + __typename?: 'AddTagPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The shop that owns the tag */ + shopId: Scalars['ID'] + /** The newly-created tag */ + tag: Tag +} + +/** Represents a physical or mailing address somewhere on Earth */ +export type Address = { + __typename?: 'Address' + /** The address ID */ + _id?: Maybe<Scalars['ID']> + /** The street address / first line */ + address1: Scalars['String'] + /** Optional second line */ + address2?: Maybe<Scalars['String']> + /** City */ + city: Scalars['String'] + /** Optional company name, if it's a business address */ + company?: Maybe<Scalars['String']> + /** Country */ + country: Scalars['String'] + /** + * The first name of a person at this address + * This is an optional field to support legacy and third party platforms + * We use fullName internally, and use first and last name fields to combine into a full name if needed + */ + firstName?: Maybe<Scalars['String']> + /** The full name of a person at this address */ + fullName: Scalars['String'] + /** Is this the default address for billing purposes? */ + isBillingDefault?: Maybe<Scalars['Boolean']> + /** Is this a commercial address? */ + isCommercial: Scalars['Boolean'] + /** Is this the default address to use when selecting a shipping address at checkout? */ + isShippingDefault?: Maybe<Scalars['Boolean']> + /** + * The last name of a person at this address + * This is an optional field to support legacy and third party platforms + * We use fullName internally, and use first and last name fields to combine into a full name if needed + */ + lastName?: Maybe<Scalars['String']> + /** Arbitrary additional metadata about this address */ + metafields?: Maybe<Array<Maybe<Metafield>>> + /** A phone number for someone at this address */ + phone: Scalars['String'] + /** Postal code */ + postal: Scalars['String'] + /** Region. For example, a U.S. state */ + region: Scalars['String'] +} + +/** + * Wraps a list of `Addresses`, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type AddressConnection = { + __typename?: 'AddressConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<AddressEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Address>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is an `Address` object */ +export type AddressEdge = { + __typename?: 'AddressEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The address */ + node?: Maybe<Address> +} + +/** The details of an `Address` to be created or updated */ +export type AddressInput = { + /** The street address / first line */ + address1: Scalars['String'] + /** Optional second line */ + address2?: Maybe<Scalars['String']> + /** Optionally, a name for this address (e.g. 'Home') to easily identify it in the future */ + addressName?: Maybe<Scalars['String']> + /** City */ + city: Scalars['String'] + /** Optional company name, if it's a business address */ + company?: Maybe<Scalars['String']> + /** Country */ + country: Scalars['String'] + /** + * The first name of a person at this address + * This is an optional field to support legacy and third party platforms + * We use fullName internally, and use first and last name fields to combine into a full name if needed + */ + firstName?: Maybe<Scalars['String']> + /** The full name of a person at this address */ + fullName: Scalars['String'] + /** Is this the default address for billing purposes? */ + isBillingDefault?: Maybe<Scalars['Boolean']> + /** Is this a commercial address? */ + isCommercial?: Maybe<Scalars['Boolean']> + /** Is this the default address to use when selecting a shipping address at checkout? */ + isShippingDefault?: Maybe<Scalars['Boolean']> + /** + * The last name of a person at this address + * This is an optional field to support legacy and third party platforms + * We use fullName internally, and use first and last name fields to combine into a full name if needed + */ + lastName?: Maybe<Scalars['String']> + /** Arbitrary additional metadata about this address */ + metafields?: Maybe<Array<Maybe<MetafieldInput>>> + /** A phone number for someone at this address */ + phone: Scalars['String'] + /** Postal code */ + postal: Scalars['String'] + /** Region. For example, a U.S. state */ + region: Scalars['String'] +} + +/** A list of the possible types of `Address` */ +export enum AddressType { + /** Address can be used for payment transactions and invoicing */ + Billing = 'billing', + /** Address can be used as a mailing address for sending physical items */ + Shipping = 'shipping', +} + +/** Details about an error that was the result of validating an address that is invalid */ +export type AddressValidationError = { + __typename?: 'AddressValidationError' + /** A longer, detailed error message suitable for showing in the user interface */ + details?: Maybe<Scalars['String']> + /** An identifier of the source of this error. These are not currently standardized. As long as your client understands it, any string is fine. */ + source?: Maybe<Scalars['String']> + /** A short error message suitable for showing in the user interface */ + summary: Scalars['String'] + /** The error type. These are not currently standardized. As long as your client understands it, any string is fine. */ + type: Scalars['String'] +} + +/** The response from `Query.addressValidation` */ +export type AddressValidationResults = { + __typename?: 'AddressValidationResults' + /** + * A list of suggested addresses. If the address is valid as is OR the address input is invalid OR + * the shop is not configured to validate addresses, then this will be empty. + */ + suggestedAddresses: Array<Maybe<SuggestedAddress>> + /** + * This may have information about the ways in which the provided address input is incomplete or invalid. + * Show these errors in the address review user interface. + */ + validationErrors: Array<Maybe<AddressValidationError>> +} + +/** + * An address validation rule specifies which validation services should run for + * which countries in each shop. + */ +export type AddressValidationRule = Node & { + __typename?: 'AddressValidationRule' + /** The rule ID */ + _id: Scalars['ID'] + /** Country codes for which this service is enabled */ + countryCodes?: Maybe<Array<Maybe<Scalars['String']>>> + /** The date and time at which this rule was created */ + createdAt: Scalars['DateTime'] + /** + * The name of one of the installed validation services. Use `addressValidationServices` + * query to get a list with more details about all installed services. + */ + serviceName: Scalars['String'] + /** ID of the shop to which this rule applies */ + shopId: Scalars['ID'] + /** The date and time at which this rule was last updated */ + updatedAt: Scalars['DateTime'] +} + +/** + * Wraps a list of `AddressValidationRules`, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type AddressValidationRuleConnection = { + __typename?: 'AddressValidationRuleConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<AddressValidationRuleEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<AddressValidationRule>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `AddressValidationRule` object */ +export type AddressValidationRuleEdge = NodeEdge & { + __typename?: 'AddressValidationRuleEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The address validation rule */ + node?: Maybe<AddressValidationRule> +} + +/** The fields by which you are allowed to sort any query that returns an `AddressValidationRuleConnection` */ +export enum AddressValidationRuleSortByField { + /** AddressValidationRule ID */ + Id = '_id', + /** Date and time at which the rule was created */ + CreatedAt = 'createdAt', + /** Service name */ + ServiceName = 'serviceName', + /** Date and time at which the rule was last updated */ + UpdatedAt = 'updatedAt', +} + +/** A single registered address validation service */ +export type AddressValidationService = { + __typename?: 'AddressValidationService' + /** Human-readable name to show operators */ + displayName: Scalars['String'] + /** Unique name to serve as a key identifying this service */ + name: Scalars['String'] + /** An optional list of all country codes that this address service supports. Null means all countries. */ + supportedCountryCodes?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** Defines a surcharge that has been applied to a Cart or Order */ +export type AppliedSurcharge = Node & { + __typename?: 'AppliedSurcharge' + /** The surcharge ID */ + _id: Scalars['ID'] + /** The amount of the surcharge */ + amount: Money + /** The fulfillmentGroupId (for reference) */ + fulfillmentGroupId?: Maybe<Scalars['ID']> + /** The message to explain the surchage to customers, translated (if available) based on shop language */ + message?: Maybe<Scalars['String']> + /** The surchargeId from the surchages collection (for reference) */ + surchargeDefinitionId: Scalars['ID'] +} + +/** Defines a surcharge that has been applied to a Cart or Order */ +export type AppliedSurchargeMessageArgs = { + language: Scalars['String'] +} + +/** Input for an `ApplyDiscountCodeToCartInput` */ +export type ApplyDiscountCodeToCartInput = { + /** Cart to add discount to */ + cartId: Scalars['ID'] + /** Discount code to add to cart */ + discountCode: Scalars['String'] + /** Shop cart belongs to */ + shopId: Scalars['ID'] + /** Cart token, if anonymous */ + token?: Maybe<Scalars['String']> +} + +/** Response from the `applyDiscountCodeToCart` mutation */ +export type ApplyDiscountCodeToCartPayload = { + __typename?: 'ApplyDiscountCodeToCartPayload' + /** The updated cart with discount code applied */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input for the `approveOrderPayments` mutation */ +export type ApproveOrderPaymentsInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The order ID */ + orderId: Scalars['ID'] + /** The IDs of one or more payments to approve for this order */ + paymentIds: Array<Maybe<Scalars['ID']>> + /** The ID of the shop that owns this order */ + shopId: Scalars['ID'] +} + +/** Response from the `approveOrderPayments` mutation */ +export type ApproveOrderPaymentsPayload = { + __typename?: 'ApproveOrderPaymentsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated order */ + order: Order +} + +/** Input for the archiveMediaRecord mutation */ +export type ArchiveMediaRecordInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of MediaRecord to archive */ + mediaRecordId: Scalars['ID'] + /** ID of shop that owns this MediaRecord */ + shopId: Scalars['ID'] +} + +/** Response payload for the archiveMediaRecord mutation */ +export type ArchiveMediaRecordPayload = { + __typename?: 'ArchiveMediaRecordPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The archived MediaRecord */ + mediaRecord: MediaRecord +} + +/** Input for the `archiveProducts` mutation */ +export type ArchiveProductVariantsInput = { + /** ID of shop that owns all variants you are archiving */ + shopId: Scalars['ID'] + /** Array of IDs of variants to archive */ + variantIds: Array<Maybe<Scalars['ID']>> +} + +/** Response payload of `archiveProductVariants` mutation */ +export type ArchiveProductVariantsPayload = { + __typename?: 'ArchiveProductVariantsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Array of newly archived variants */ + variants: Array<Maybe<ProductVariant>> +} + +/** Input for the `archiveProducts` mutation */ +export type ArchiveProductsInput = { + /** Array of IDs of products to archive */ + productIds: Array<Maybe<Scalars['ID']>> + /** ID of shop that owns all products you are archiving */ + shopId: Scalars['ID'] +} + +/** Response payload of `archiveProducts` mutation */ +export type ArchiveProductsPayload = { + __typename?: 'ArchiveProductsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Array of newly archived products */ + products: Array<Maybe<Product>> +} + +/** An attribute restriction condition */ +export type AttributeRestrictions = { + __typename?: 'AttributeRestrictions' + /** The operator to use for value comparison */ + operator: Scalars['String'] + /** The property to check */ + property: Scalars['String'] + /** The type of this property */ + propertyType: Scalars['String'] + /** The value to check for */ + value: Scalars['String'] +} + +/** Input to create an attribute restriction condition */ +export type AttributeRestrictionsInput = { + /** The operator to use for value comparison */ + operator: Scalars['String'] + /** The property to check */ + property: Scalars['String'] + /** The type of this property */ + propertyType: Scalars['String'] + /** The value to check for */ + value: Scalars['String'] +} + +export type AuthenticateParamsInput = { + access_token?: Maybe<Scalars['String']> + access_token_secret?: Maybe<Scalars['String']> + provider?: Maybe<Scalars['String']> + password?: Maybe<Scalars['String']> + user?: Maybe<UserInput> + code?: Maybe<Scalars['String']> +} + +/** A single calculated tax for a cart, order group, cart item, or order item */ +export type CalculatedTax = { + __typename?: 'CalculatedTax' + /** Calculated tax ID */ + _id: Scalars['ID'] + /** Jurisdiction ID. It is up to the tax service to determine if and how to use this. */ + jurisdictionId?: Maybe<Scalars['String']> + /** Did this tax match due to the order origin or the order destination? */ + sourcing: TaxSource + /** Amount of tax due */ + tax: Money + /** A human-readable display name for showing this tax to operators and customers in the UI */ + taxName: Scalars['String'] + /** The tax rate used for this calculation */ + taxRate: Rate + /** Amount that was used for calculating the tax due */ + taxableAmount: Money +} + +/** Input for the cancelOrderItem mutation */ +export type CancelOrderItemInput = { + /** Quantity to cancel. Must be equal to or less than the item quantity. */ + cancelQuantity: Scalars['Int'] + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of the item order you want to cancel */ + itemId: Scalars['ID'] + /** ID of the order that has the item you want to cancel */ + orderId: Scalars['ID'] + /** + * An optional free text reason for cancellation, which may be shown to operators + * or to the user who placed the order. + */ + reason?: Maybe<Scalars['String']> +} + +/** Response payload for the cancelOrderItem mutation */ +export type CancelOrderItemPayload = { + __typename?: 'CancelOrderItemPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated order */ + order: Order +} + +/** Input for the `captureOrderPayments` mutation */ +export type CaptureOrderPaymentsInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The order ID */ + orderId: Scalars['ID'] + /** The IDs of one or more payments to capture for this order */ + paymentIds: Array<Maybe<Scalars['ID']>> + /** The ID of the shop that owns this order */ + shopId: Scalars['ID'] +} + +/** Response from the `captureOrderPayments` mutation */ +export type CaptureOrderPaymentsPayload = { + __typename?: 'CaptureOrderPaymentsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated order */ + order: Order +} + +/** The cart holds selected items until order is placed. */ +export type Cart = Node & { + __typename?: 'Cart' + /** The Cart ID */ + _id: Scalars['ID'] + /** + * The account that owns the cart. Some carts are created for anonymous users. Anonymous carts have a null account. + * Every account has exactly one cart per shop. + */ + account?: Maybe<Account> + /** Holds all information collected for a cart during checkout */ + checkout?: Maybe<Checkout> + /** The date and time at which the cart was created, which is when the first item was added to it. */ + createdAt: Scalars['DateTime'] + /** An email address that has been associated with the cart */ + email?: Maybe<Scalars['String']> + /** The date and time at which the cart will expire. Account carts usually do not expire, so they will have a null value here. */ + expiresAt?: Maybe<Scalars['DateTime']> + /** The items that have been added to the cart. A cart is not created until the first item is added. Items can be removed from a cart, and a cart is not deleted if all items are removed from it. Because all items may have been removed, this may be an empty array. */ + items?: Maybe<CartItemConnection> + /** + * If any products or variants become hidden or are deleted after they were added to this cart, they'll be + * automatically moved from `items` to `missingItems`. Clients may want to use this to show an + * "items that are no longer available" list to storefront users. + * + * If a product becomes visible again, the item will never be automatically moved from `missingItems` + * back to `items`, but clients may want to provide a way for users to manually do this. + */ + missingItems?: Maybe<Array<Maybe<CartItem>>> + /** + * If you integrate with third-party systems that require you to send the same ID for order + * calculations as for cart calculations, you may use this ID, which is the same on a `cart` as on + * the `order` placed from that cart. This ID can also be customized by plugins and is the best + * ID to use if it is necessary to show a cart ID in the user interface. + */ + referenceId?: Maybe<Scalars['String']> + /** The shop that owns the cart. */ + shop: Shop + /** Total quantity of all items in the cart */ + totalItemQuantity: Scalars['Int'] + /** The date and time at which this cart was last updated. */ + updatedAt: Scalars['DateTime'] + /** Surcharges applied to this cart */ + surcharges: Array<Maybe<AppliedSurcharge>> + /** + * A summary of calculated taxes for this cart. Null means "not able to calculate", + * such as when no fulfillment method has been selected for some fulfillment groups. + */ + taxSummary?: Maybe<TaxSummary> +} + +/** The cart holds selected items until order is placed. */ +export type CartItemsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<CartItemsSortByField> +} + +/** A single item in a cart. The item contains information about an intended purchase. */ +export type CartItem = Node & { + __typename?: 'CartItem' + /** The cart item ID */ + _id: Scalars['ID'] + /** + * " + * The date and time at which this item was first added to the associated cart. + * If an item is added, removed, and then added again, this will reflect the most recent addition. + * However, if an item is added twice, the quantity will increase but this date will remain + * the initial added date. + */ + addedAt: Scalars['DateTime'] + /** + * FUTURE. Additional attributes of the chosen item. For example, if this item is for a product, socks, where `blue` and `small` + * options were chosen for some configurable attributes, then `color:blue` and `size:small` will be indicated here. + */ + attributes?: Maybe<Array<Maybe<CartItemAttribute>>> + /** The current comparison (e.g., MSRP) price of the item */ + compareAtPrice?: Maybe<Money> + /** + * The date and time at which the cart item was created. If an item is added, removed, and then added again, + * the original item is destroyed and this field will reflect the time it was created for the most recent addition. + */ + createdAt: Scalars['DateTime'] + /** The URLs for a picture of the item in various sizes */ + imageURLs?: Maybe<ImageSizes> + /** Arbitrary additional metadata about this cart item. */ + metafields?: Maybe<Array<Maybe<Metafield>>> + /** The selected variant optionTitle */ + optionTitle?: Maybe<Scalars['String']> + /** Packing information such as item weight, height, length, and depth. Used for calculating shipping rates. */ + parcel?: Maybe<ShippingParcel> + /** The current price of the item */ + price: Money + /** The price at which this item was listed when it was added to the cart */ + priceWhenAdded: Money + /** The product and chosen options */ + productConfiguration: ProductConfiguration + /** The product's slug */ + productSlug?: Maybe<Scalars['String']> + /** The list of tags that have been applied to this product */ + productTags?: Maybe<TagConnection> + /** The type of product, used to display cart items differently */ + productType?: Maybe<Scalars['String']> + /** The product vendor */ + productVendor?: Maybe<Scalars['String']> + /** The quantity of this item that has been added to the cart. This must be a positive integer. Remove this `CartItem` from it's associated cart if you want `0` of this item. */ + quantity: Scalars['Int'] + /** The shop associated with this cart item. */ + shop: Shop + /** The current price of the item multiplied by the quantity */ + subtotal: Money + /** A title for use in cart/orders that conveys the selected product's title + chosen options */ + title: Scalars['String'] + /** The date and time at which this item was last updated */ + updatedAt: Scalars['DateTime'] + /** The selected variant title */ + variantTitle?: Maybe<Scalars['String']> + /** + * The quantity of this item currently available to sell. + * This number is updated when an order is placed by the customer. + * This number does not include reserved inventory (i.e. inventory that has been ordered, but not yet processed by the operator). + * This is most likely the quantity to display in the storefront UI. + */ + inventoryAvailableToSell?: Maybe<Scalars['Int']> + /** + * True if this item is currently sold out but allows backorders. A storefront UI may use this + * to decide to show a "Backordered" indicator. + */ + isBackorder: Scalars['Boolean'] + /** + * True if this item has a low available quantity (`inventoryAvailableToSell`) in stock. + * A storefront UI may use this to decide to show a "Low Quantity" indicator. + */ + isLowQuantity: Scalars['Boolean'] + /** + * True if this item is currently sold out (`inventoryAvailableToSell` is 0). A storefront + * UI may use this to decide to show a "Sold Out" indicator when `isBackorder` is not also true. + */ + isSoldOut: Scalars['Boolean'] + /** Is this a taxable item? */ + isTaxable: Scalars['Boolean'] + /** Total tax calculated for this item */ + tax?: Maybe<Money> + /** The tax code for this item */ + taxCode?: Maybe<Scalars['String']> + /** Amount of subtotal that is taxable */ + taxableAmount?: Maybe<Money> + /** List of calculated taxes due for this item */ + taxes?: Maybe<Array<Maybe<CalculatedTax>>> +} + +/** A single item in a cart. The item contains information about an intended purchase. */ +export type CartItemProductTagsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<TagSortByField> +} + +/** One attribute of a cart item */ +export type CartItemAttribute = { + __typename?: 'CartItemAttribute' + /** The attribute label, e.g., Color */ + label?: Maybe<Scalars['String']> + /** The attribute value, e.g., Blue */ + value?: Maybe<Scalars['String']> +} + +/** + * Wraps a list of `CartItem`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type CartItemConnection = { + __typename?: 'CartItemConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<CartItemEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<CartItem>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `CartItem` object */ +export type CartItemEdge = NodeEdge & { + __typename?: 'CartItemEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The cart item */ + node?: Maybe<CartItem> +} + +/** Information about an item to add to a cart */ +export type CartItemInput = { + /** Arbitrary additional metadata about this cart item. */ + metafields?: Maybe<Array<Maybe<MetafieldInput>>> + /** + * The price of this item, for validating that this matches the actual price in the system, + * in case the client has stale data. + */ + price: MoneyInput + /** The product and chosen options */ + productConfiguration: ProductConfigurationInput + /** The number of this item to add to the cart */ + quantity: Scalars['Int'] +} + +/** Allowed values for cart item sortBy parameter */ +export enum CartItemsSortByField { + /** Cart item ID */ + Id = '_id', + /** Date and time at which the item was added to the cart */ + AddedAt = 'addedAt', +} + +/** Supported cart reconciliation modes */ +export enum CartReconciliationMode { + /** Delete the anonymous cart and use the account cart. */ + KeepAccountCart = 'keepAccountCart', + /** Assign the anonymous cart to the account, and delete the account cart. */ + KeepAnonymousCart = 'keepAnonymousCart', + /** + * Move all items from the anonymous cart into the account cart along with existing + * account cart items. If the same item is in both carts, combine the quantities. + */ + Merge = 'merge', +} + +/** A summary of the totals for this cart */ +export type CartSummary = { + __typename?: 'CartSummary' + /** The total of all discounts applied, as a positive number */ + discountTotal: Money + /** + * The calculated tax-exclusive tax rate on all items and fulfillment prices (taxTotal / taxableAmount). + * This may be null, and there is a difference between null and 0. Null means `not able to calculate`, + * such as when no fulfillment method has been selected for some fulfillment groups. + */ + effectiveTaxRate?: Maybe<Rate> + /** + * The total price of all chosen fulfillment methods. This may be null, and there is a difference + * between null and 0. Null means `not able to calculate`, such as when no fulfillment method has + * been selected for some fulfillment groups. + */ + fulfillmentTotal?: Maybe<Money> + /** The combined prices of all cart items */ + itemTotal: Money + /** + * The total estimated tax that has not already been included in the item prices. This may be null, + * and there is a difference between null and 0. Null means `not able to calculate`, such as when no + * fulfillment methods have been selected or there is some other issue with the tax service. + */ + taxTotal?: Maybe<Money> + /** The total amount that was deemed taxable by the tax service */ + taxableAmount: Money + /** The sum of `itemTotal`, `fulfillmentTotal`, and `taxTotal`, minus `discountTotal` */ + total: Money + /** + * The combined total of all surcharges. This may be null, and there is a difference + * between null and 0. Null means `not able to calculate`, such as when no fulfillment method has + * been selected for some fulfillment groups. + */ + surchargeTotal?: Maybe<Money> +} + +/** One product catalog for a particular shop */ +export type Catalog = Node & { + __typename?: 'Catalog' + /** The Catalog ID */ + _id: Scalars['ID'] + /** The date and time at which this Catalog was first created */ + createdAt: Scalars['DateTime'] + /** The shop to which this catalog belongs */ + shop: Shop + /** The date and time at which this Catalog was last updated */ + updatedAt: Scalars['DateTime'] +} + +/** A filter to be applied to a Catalog query */ +export type CatalogBooleanFilter = { + /** The name of the filter */ + name: CatalogBooleanFilterName + /** The filter value */ + value: Scalars['Boolean'] +} + +/** The list of currently supported top level Catalog props on which catalog items can be filtered. */ +export enum CatalogBooleanFilterName { + /** isDeleted */ + IsDeleted = 'isDeleted', + /** isVisible */ + IsVisible = 'isVisible', + /** isLowQuantity */ + IsLowQuantity = 'isLowQuantity', + /** isSoldOut */ + IsSoldOut = 'isSoldOut', + /** isBackorder */ + IsBackorder = 'isBackorder', +} + +/** Catalog items are combined to create a catalog. Each item can represent a different type of content. */ +export type CatalogItem = { + /** Item ID */ + _id: Scalars['ID'] + /** Date and time at which the item was created */ + createdAt?: Maybe<Scalars['DateTime']> + /** Shop that owns the item */ + shop: Shop + /** Date and time at which the item was last updated */ + updatedAt?: Maybe<Scalars['DateTime']> +} + +/** + * Wraps a list of `CatalogItem`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type CatalogItemConnection = { + __typename?: 'CatalogItemConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<CatalogItemEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<CatalogItem>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** Represents a catalog item that displays some non-product content */ +export type CatalogItemContent = CatalogItem & + Node & { + __typename?: 'CatalogItemContent' + /** The CatalogItemProduct ID */ + _id: Scalars['ID'] + /** The date and time at which this CatalogItem was first created */ + createdAt: Scalars['DateTime'] + /** The shop to which this catalog belongs */ + shop: Shop + /** The date and time at which this CatalogItem was last updated */ + updatedAt: Scalars['DateTime'] + } + +/** A connection edge in which each node is a `CatalogItem` object */ +export type CatalogItemEdge = { + __typename?: 'CatalogItemEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The catalog item */ + node?: Maybe<CatalogItem> +} + +/** Represents a catalog item that displays a product */ +export type CatalogItemProduct = CatalogItem & + Node & { + __typename?: 'CatalogItemProduct' + /** The CatalogItemProduct ID */ + _id: Scalars['ID'] + /** The date and time at which this CatalogItem was first created, which is when the related product was first published */ + createdAt: Scalars['DateTime'] + /** The catalog product */ + product?: Maybe<CatalogProduct> + /** The shop to which this catalog belongs */ + shop: Shop + /** The date and time at which this CatalogItem was last updated, which is when the related product was most recently published */ + updatedAt: Scalars['DateTime'] + } + +/** Allowed values for sorting catalog items */ +export enum CatalogItemSortByField { + /** Sort by item ID */ + Id = '_id', + /** Sort by date and time at which the item was created */ + CreatedAt = 'createdAt', + /** Sort in the shop-defined order for the tag filter */ + Featured = 'featured', + /** Sort by price */ + MinPrice = 'minPrice', + /** Sort by date and time at which the item was last updated */ + UpdatedAt = 'updatedAt', +} + +/** + * Represents a product that has been published into a shop catalog. The related `Product` is the source of truth for + * shop administrators, but that is then published to a catalog as a `CatalogProduct`, which is what should + * be displayed to shoppers who browse that catalog. + */ +export type CatalogProduct = CatalogProductOrVariant & + Node & { + __typename?: 'CatalogProduct' + /** The CatalogProduct ID. Do not assume that this is the same as the related product ID. See `productId` for that. */ + _id: Scalars['ID'] + /** The product barcode value, if it has one */ + barcode?: Maybe<Scalars['String']> + /** The date and time at which this CatalogProduct was created, which is when the related product was first published */ + createdAt: Scalars['DateTime'] + /** The full product description, which may have newline characters in it */ + description?: Maybe<Scalars['String']> + /** The height of the product, if it has physical dimensions */ + height?: Maybe<Scalars['Float']> + /** True if this product has been deleted. Typically, deleted products are not returned in queries. */ + isDeleted: Scalars['Boolean'] + /** True if this product should be shown to shoppers. Typically, non-visible products are not returned in queries. */ + isVisible: Scalars['Boolean'] + /** The length of the product, if it has physical dimensions */ + length?: Maybe<Scalars['Float']> + /** All media for this product and its variants */ + media?: Maybe<Array<Maybe<ImageInfo>>> + /** The product description to use for page `description` meta element in HTML */ + metaDescription?: Maybe<Scalars['String']> + /** Arbitrary additional metadata about this product */ + metafields?: Maybe<Array<Maybe<Metafield>>> + /** The minimum quantity that must be added to a cart */ + minOrderQuantity?: Maybe<Scalars['Int']> + /** The country of origin */ + originCountry?: Maybe<Scalars['String']> + /** Subtitle */ + pageTitle?: Maybe<Scalars['String']> + /** Dimensions and other information about the containers in which this product will be shipped */ + parcel?: Maybe<ShippingParcel> + /** The primary image */ + primaryImage?: Maybe<ImageInfo> + /** The related Product ID */ + productId: Scalars['ID'] + /** An arbitrary product type value, such as from an external system */ + productType?: Maybe<Scalars['String']> + /** The shop to which this product belongs */ + shop: Shop + /** A stock keeping unit (SKU) identifier for this product */ + sku?: Maybe<Scalars['String']> + /** A URL-safe and human-readable string that uniquely identifies this product */ + slug?: Maybe<Scalars['String']> + /** Holds metadata specific to a specific social network service */ + socialMetadata?: Maybe<Array<Maybe<SocialMetadata>>> + /** When a shopper purchases this product, what types of fulfillment can they choose from? */ + supportedFulfillmentTypes: Array<Maybe<FulfillmentType>> + /** Product title */ + title?: Maybe<Scalars['String']> + /** The date and time at which this CatalogProduct was last updated, which is when the related product was most recently published */ + updatedAt: Scalars['DateTime'] + /** A flat list of all variants for this product */ + variants?: Maybe<Array<Maybe<CatalogProductVariant>>> + /** The product vendor or manufacturer, for display */ + vendor?: Maybe<Scalars['String']> + /** The weight of the product on Earth, if it has physical dimensions */ + weight?: Maybe<Scalars['Float']> + /** The width of the product, if it has physical dimensions */ + width?: Maybe<Scalars['Float']> + /** The list of tag IDs that have been applied to this product */ + tagIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** The list of tags that have been applied to this product */ + tags?: Maybe<TagConnection> + /** Price and related information, per currency */ + pricing: Array<Maybe<ProductPricingInfo>> + /** + * True if every purchasable variant of this product is sold out but allows backorders. A storefront UI may use this + * to decide to show a "Backordered" indicator. + */ + isBackorder: Scalars['Boolean'] + /** + * True if at least one purchasable variant of this product has a low quantity in stock. A storefront UI may use this + * to decide to show a "Low Quantity" indicator. + */ + isLowQuantity: Scalars['Boolean'] + /** + * True if every purchasable variant of this product is sold out. A storefront UI may use this + * to decide to show a "Sold Out" indicator when `isBackorder` is not also true. + */ + isSoldOut: Scalars['Boolean'] + } + +/** + * Represents a product that has been published into a shop catalog. The related `Product` is the source of truth for + * shop administrators, but that is then published to a catalog as a `CatalogProduct`, which is what should + * be displayed to shoppers who browse that catalog. + */ +export type CatalogProductTagsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<TagSortByField> +} + +/** This interface represents the fields that are identical for both Products and Variants */ +export type CatalogProductOrVariant = { + /** The product barcode value, if it has one */ + barcode?: Maybe<Scalars['String']> + /** The date and time at which this CatalogProduct was created, which is when the related product was first published */ + createdAt?: Maybe<Scalars['DateTime']> + /** The height of the product, if it has physical dimensions */ + height?: Maybe<Scalars['Float']> + /** The length of the product, if it has physical dimensions */ + length?: Maybe<Scalars['Float']> + /** Arbitrary additional metadata about this product */ + metafields?: Maybe<Array<Maybe<Metafield>>> + /** The minimum quantity that must be added to a cart */ + minOrderQuantity?: Maybe<Scalars['Int']> + /** The country of origin */ + originCountry?: Maybe<Scalars['String']> + /** The shop to which this product belongs */ + shop: Shop + /** A stock keeping unit (SKU) identifier for this product */ + sku?: Maybe<Scalars['String']> + /** Product or variant title */ + title?: Maybe<Scalars['String']> + /** The date and time at which this CatalogProduct was last updated, which is when the related product was most recently published */ + updatedAt?: Maybe<Scalars['DateTime']> + /** The weight of the product on Earth, if it has physical dimensions */ + weight?: Maybe<Scalars['Float']> + /** The width of the product, if it has physical dimensions */ + width?: Maybe<Scalars['Float']> +} + +/** A variant of a catalog product */ +export type CatalogProductVariant = CatalogProductOrVariant & + Node & { + __typename?: 'CatalogProductVariant' + /** The CatalogProductVariant ID. Do not assume that this is the same as the related variant ID. See `variantId` for that. */ + _id: Scalars['ID'] + /** + * The attribute label describes the category of variant, for example, `Color` or `Size`. + * In most cases this will be the same for all variants at the same level. + */ + attributeLabel: Scalars['String'] + /** The product variant barcode value, if it has one */ + barcode?: Maybe<Scalars['String']> + /** The date and time at which this CatalogProductVariant was created, which is when the related product was first published */ + createdAt?: Maybe<Scalars['DateTime']> + /** The height of the product variant, if it has physical dimensions */ + height?: Maybe<Scalars['Float']> + /** The position of this variant among other variants at the same level of the product-variant-option hierarchy */ + index: Scalars['Int'] + /** The length of the product, if it has physical dimensions */ + length?: Maybe<Scalars['Float']> + /** All media for this variant / option */ + media?: Maybe<Array<Maybe<ImageInfo>>> + /** Arbitrary additional metadata about this product */ + metafields?: Maybe<Array<Maybe<Metafield>>> + /** The minimum quantity that must be added to a cart */ + minOrderQuantity?: Maybe<Scalars['Int']> + /** A short title to use for product detail select lists */ + optionTitle?: Maybe<Scalars['String']> + /** Child variants, if any */ + options?: Maybe<Array<Maybe<CatalogProductVariant>>> + /** The country of origin */ + originCountry?: Maybe<Scalars['String']> + /** The primary image of this variant / option */ + primaryImage?: Maybe<ImageInfo> + /** The shop to which this product variant belongs */ + shop: Shop + /** A stock keeping unit (SKU) identifier for this product */ + sku?: Maybe<Scalars['String']> + /** + * The full variant title for use on cart, checkout, and order summaries and on invoices. + * This fully describes the configured variant. For example, if this is an option with + * `optionTitle` `Large`, its parent variant has `optionTitle` `Red`, and the product + * `title` is `Fancy T-Shirt`, then this `title` will be something like `Fancy T-Shirt - Red - Large`. + */ + title?: Maybe<Scalars['String']> + /** The date and time at which this CatalogProduct was last updated, which is when the related product was most recently published */ + updatedAt?: Maybe<Scalars['DateTime']> + /** The related Variant ID */ + variantId: Scalars['ID'] + /** The weight of the product on Earth, if it has physical dimensions */ + weight?: Maybe<Scalars['Float']> + /** The width of the product, if it has physical dimensions */ + width?: Maybe<Scalars['Float']> + /** Price and related information, per currency */ + pricing: Array<Maybe<ProductPricingInfo>> + /** + * True for a purchasable variant if an order containing this variant will be accepted even when there is insufficient + * available inventory (`inventoryAvailableToSell`) to fulfill it immediately. For non-purchasable variants, this is true if at least one purchasable + * child variant can be backordered. A storefront UI may use this in combination with `inventoryAvailableToSell` to + * decide whether to show or enable an "Add to Cart" button. + */ + canBackorder: Scalars['Boolean'] + /** + * The quantity of this item currently available to sell. + * This number is updated when an order is placed by the customer. + * This number does not include reserved inventory (i.e. inventory that has been ordered, but not yet processed by the operator). + * If this is a variant, this number is created by summing all child option inventory numbers. + * This is most likely the quantity to display in the storefront UI. + */ + inventoryAvailableToSell?: Maybe<Scalars['Int']> + /** + * The quantity of this item currently in stock. + * This number is updated when an order is processed by the operator. + * This number includes all inventory, including reserved inventory (i.e. inventory that has been ordered, but not yet processed by the operator). + * If this is a variant, this number is created by summing all child option inventory numbers. + * This is most likely just used as a reference in the operator UI, and not displayed in the storefront UI. + */ + inventoryInStock?: Maybe<Scalars['Int']> + /** + * True for a purchasable variant if it is sold out but allows backorders. For non-purchasable variants, this is + * true if every purchasable child variant is sold out but allows backorders. A storefront UI may use this + * to decide to show a "Backordered" indicator. + */ + isBackorder: Scalars['Boolean'] + /** + * True for a purchasable variant if it has a low available quantity (`inventoryAvailableToSell`) in stock. + * For non-purchasable variants, this is true if at least one purchasable child variant has a low available + * quantity in stock. A storefront UI may use this to decide to show a "Low Quantity" indicator. + */ + isLowQuantity: Scalars['Boolean'] + /** + * True for a purchasable variant if it is sold out (`inventoryAvailableToSell` is 0). For non-purchasable + * variants, this is true if every purchasable child variant is sold out. A storefront UI may use this + * to decide to show a "Sold Out" indicator when `isBackorder` is not also true. + */ + isSoldOut: Scalars['Boolean'] + /** Is sales tax charged on this item? */ + isTaxable: Scalars['Boolean'] + /** An optional code which, if understood by the active tax service for the shop, determines how this product should be taxed */ + taxCode?: Maybe<Scalars['String']> + /** A description to use for the tax line item on an invoice */ + taxDescription?: Maybe<Scalars['String']> + } + +/** Holds all information collected for a cart during checkout */ +export type Checkout = { + __typename?: 'Checkout' + /** One or more fulfillment groups, for example, mapping certain items to certain shipping addresses */ + fulfillmentGroups: Array<Maybe<FulfillmentGroup>> + /** A summary of the totals for this cart */ + summary: CartSummary +} + +/** Input for the `cloneProductVariants` mutation */ +export type CloneProductVariantsInput = { + /** ID of shop that owns all product variants you want to clone */ + shopId: Scalars['ID'] + /** Array of IDs of variants to clone */ + variantIds: Array<Maybe<Scalars['ID']>> +} + +/** Response payload of `cloneProductVariants` mutation */ +export type CloneProductVariantsPayload = { + __typename?: 'CloneProductVariantsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Array of newly cloned product variants */ + variants: Array<Maybe<ProductVariant>> +} + +/** Input for the `cloneProducts` mutation */ +export type CloneProductsInput = { + /** Array of IDs of products to clone */ + productIds: Array<Maybe<Scalars['ID']>> + /** ID of shop that owns all products you are cloning */ + shopId: Scalars['ID'] +} + +/** Response payload of `cloneProducts` mutation */ +export type CloneProductsPayload = { + __typename?: 'CloneProductsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Array of newly cloned products */ + products: Array<Maybe<Product>> +} + +/** The details for creating a group */ +export type CreateAccountGroupInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The group to create */ + group: GroupInput + /** The ID of the shop this group belongs to */ + shopId?: Maybe<Scalars['ID']> +} + +/** The response from the `createAccountGroup` mutation */ +export type CreateAccountGroupPayload = { + __typename?: 'CreateAccountGroupPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The new group */ + group?: Maybe<Group> +} + +/** Defines the account which should be created */ +export type CreateAccountInput = { + /** Bio to display on profile */ + bio?: Maybe<Scalars['String']> + /** Email record to create account with */ + emails: Array<Maybe<EmailRecordInput>> + /** Name to display on profile */ + name?: Maybe<Scalars['String']> + /** URL of picture to display on profile */ + picture?: Maybe<Scalars['String']> + /** The ID of the shop this account will belong to */ + shopId: Scalars['ID'] + /** The userID account was created from create a new account from */ + userId: Scalars['ID'] + /** Username */ + username?: Maybe<Scalars['String']> +} + +/** The response from the `createAccount` mutation */ +export type CreateAccountPayload = { + __typename?: 'CreateAccountPayload' + /** The added account */ + account?: Maybe<Account> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input for the `createAddressValidationRule` mutation */ +export type CreateAddressValidationRuleInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Country codes for which this service is enabled. `null` means all, while an empty array means none. */ + countryCodes?: Maybe<Array<Maybe<Scalars['String']>>> + /** + * The name of one of the installed validation services. Use `addressValidationServices` + * query to get a list, and then use the `name` field value from one of them. + */ + serviceName: Scalars['String'] + /** ID of the shop to which this rule applies */ + shopId: Scalars['ID'] +} + +/** Payload for the `createAddressValidationRule` mutation */ +export type CreateAddressValidationRulePayload = { + __typename?: 'CreateAddressValidationRulePayload' + /** Created address validation rule */ + addressValidationRule: AddressValidationRule + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** The input necessary to create a cart */ +export type CreateCartInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Array of items to add to new cart. */ + items: Array<Maybe<CartItemInput>> + /** ShopId association for the cart. */ + shopId: Scalars['ID'] +} + +/** The payload returned from the `createCart` mutation call */ +export type CreateCartPayload = { + __typename?: 'CreateCartPayload' + /** + * The created cart, if at least one item could be added. Otherwise null, and you should check + * `incorrectPriceFailures` and `minOrderQuantityFailures` for information necessary to display + * errors to the shopper. + */ + cart?: Maybe<Cart> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** + * Clients should check to see if any items failed to be added due to the price not matching the current price. + * In general, a user interface should display the correct current prices to the shopper, confirm that they still + * want to add the items, and then call `createCart` or `addCartItems` to do so. + * + * Note that this field will always exist but may be an empty array if there were no failures of this type. + */ + incorrectPriceFailures: Array<Maybe<IncorrectPriceFailureDetails>> + /** + * Clients should check to see if any items failed to be added due to quantity being below the minimum order + * quantity defined for the product variant. In general, a user interface should display the minimum order + * quantity to the shopper and allow them to add that quantity or greater. + * + * Note that this field will always exist but may be an empty array if there were no failures of this type. + */ + minOrderQuantityFailures: Array<Maybe<MinOrderQuantityFailureDetails>> + /** + * If no identity token is provided with the request, then this mutation will create an anonymous cart. All + * anonymous carts have a token associated with them, which allows the client that created the cart to access + * that cart in the future. This is the only time this token is returned, so clients must store this securely + * in some type of local storage solution, and then send it along with all future anonymous cart queries and + * mutations. + */ + token?: Maybe<Scalars['String']> +} + +/** Describes the input for creating a discount code */ +export type CreateDiscountCodeInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The discount code to update */ + discountCode?: Maybe<DiscountCodeInput> + /** The shop ID of the discount code to update */ + shopId: Scalars['ID'] +} + +/** The response from the `createDiscountCode` mutation */ +export type CreateDiscountCodePayload = { + __typename?: 'CreateDiscountCodePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created discount code */ + discountCode?: Maybe<DiscountCode> +} + +/** Input for the `createFlatRateFulfillmentMethod` mutation */ +export type CreateFlatRateFulfillmentMethodInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** This defines the flat rate fulfillment method that you want to create */ + method: FlatRateFulfillmentMethodInput + /** The shop to create this flat rate fulfillment method for */ + shopId: Scalars['ID'] +} + +/** Response from the `createFlatRateFulfillmentMethod` mutation */ +export type CreateFlatRateFulfillmentMethodPayload = { + __typename?: 'CreateFlatRateFulfillmentMethodPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created fulfillment method */ + method: FlatRateFulfillmentMethod +} + +/** Input for the `CreateFlatRateFulfillmentRestriction` mutation */ +export type CreateFlatRateFulfillmentRestrictionInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** This defines the flat rate fulfillment method restriction that you want to create */ + restriction: FlatRateFulfillmentRestrictionInput + /** The shop to create this flat rate fulfillment method restriction for */ + shopId: Scalars['ID'] +} + +/** Response from the `CreateFlatRateFulfillmentRestriction` mutation */ +export type CreateFlatRateFulfillmentRestrictionPayload = { + __typename?: 'CreateFlatRateFulfillmentRestrictionPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created flat rate fulfillment method restriction */ + restriction: FlatRateFulfillmentRestriction +} + +/** Input for the createMediaRecord mutation */ +export type CreateMediaRecordInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The media record to insert, with related file data already fully uploaded to temporary storage */ + mediaRecord: MediaRecordInput + /** ID of shop that owns this MediaRecord */ + shopId: Scalars['ID'] +} + +/** Response payload for the createMediaRecord mutation */ +export type CreateMediaRecordPayload = { + __typename?: 'CreateMediaRecordPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created MediaRecord */ + mediaRecord: MediaRecord +} + +/** Input for the `createNavigationItem` mutation */ +export type CreateNavigationItemInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The navigation item to create */ + navigationItem: NavigationItemInput +} + +/** Response payload for the `createNavigationItem` mutation */ +export type CreateNavigationItemPayload = { + __typename?: 'CreateNavigationItemPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created navigation item */ + navigationItem?: Maybe<NavigationItem> +} + +/** Input for the `createNavigationTree` mutation */ +export type CreateNavigationTreeInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The draft navigation items that make up this tree */ + draftItems?: Maybe<Array<Maybe<NavigationTreeItemInput>>> + /** The name of the tree, for operator display purposes */ + name: Scalars['String'] + /** The ID of the shop this navigation tree belongs to */ + shopId: Scalars['ID'] +} + +/** Response payload for the `createNavigationTree` mutation */ +export type CreateNavigationTreePayload = { + __typename?: 'CreateNavigationTreePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created navigation tree */ + navigationTree: NavigationTree +} + +/** Input for the `createProduct` mutation */ +export type CreateProductInput = { + /** Product input */ + product?: Maybe<ProductInput> + /** ID of shop product will belong to */ + shopId: Scalars['ID'] + /** Set to false if you do not want to auto-create the first variant of the product */ + shouldCreateFirstVariant?: Maybe<Scalars['Boolean']> +} + +/** Response payload of `createProduct` mutation */ +export type CreateProductPayload = { + __typename?: 'CreateProductPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created product */ + product: Product +} + +/** Input for the `createProductVariant` mutation */ +export type CreateProductVariantInput = { + /** ID of product variant belongs to */ + productId: Scalars['ID'] + /** ID of shop product variant will belong to */ + shopId: Scalars['ID'] + /** Variant input */ + variant?: Maybe<ProductVariantInput> +} + +/** Response payload of `createProductVariant` mutation */ +export type CreateProductVariantPayload = { + __typename?: 'CreateProductVariantPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created product variant */ + variant: ProductVariant +} + +/** Input for the cancelOrderItem mutation */ +export type CreateRefundInput = { + /** Amount to cancel. Must be equal to or less than the remaining non-refunded payment amount for this payment method. */ + amount: Scalars['Float'] + /** ID of the order that has the item you want to cancel */ + orderId: Scalars['ID'] + /** ID of the payment that you want to refund */ + paymentId: Scalars['ID'] + /** + * An optional free text reason for refund, which may be shown to operators + * or to the user who requested the refund. + */ + reason?: Maybe<Scalars['String']> +} + +/** Response payload for the createRefund mutation */ +export type CreateRefundPayload = { + __typename?: 'CreateRefundPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated order */ + order: Order +} + +/** Input parameters for the `createShop` mutation */ +export type CreateShopInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Currency in which all money values should be assumed to be. Default is `USD`. */ + currencyCode?: Maybe<Scalars['String']> + /** Default language for translation and localization. Default is `en`. */ + defaultLanguage?: Maybe<Scalars['String']> + /** Primary timezone. Default is `US/Pacific` */ + defaultTimezone?: Maybe<Scalars['String']> + /** An optional description of the shop, intended for only admins to see */ + description?: Maybe<Scalars['String']> + /** A unique name for the shop */ + name: Scalars['String'] + /** The shop type. Default is `primary`, but there may be only one primary shop. */ + type?: Maybe<Scalars['String']> +} + +/** The response from the `createShop` mutation */ +export type CreateShopPayload = { + __typename?: 'CreateShopPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The shop which was created */ + shop: Shop +} + +/** Input for the `CreateSurcharge` mutation */ +export type CreateSurchargeInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The shop to create this surcharge for */ + shopId: Scalars['ID'] + /** This defines the surcharge that you want to create */ + surcharge: SurchargeInput +} + +/** Response from the `CreateSurcharge` mutation */ +export type CreateSurchargePayload = { + __typename?: 'CreateSurchargePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created surcharge */ + surcharge: Surcharge +} + +/** The input for creating a tax rate */ +export type CreateTaxRateInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** An optional country code to limit where this tax is applied based on destination address */ + country?: Maybe<Scalars['String']> + /** An optional postal code to limit where this tax is applied based on destination address */ + postal?: Maybe<Scalars['String']> + /** The tax rate. For example, 0.05 for a 5% sales tax. */ + rate: Scalars['Float'] + /** An optional region (e.g., state) to limit where this tax is applied based on destination address */ + region?: Maybe<Scalars['String']> + /** Shop ID */ + shopId: Scalars['ID'] + /** Whether the `country`, `postal`, and `region` filters apply to the origin address or the destination address */ + sourcing?: Maybe<TaxSource> + /** An optional tax code, to apply this tax rate to only products that have this tax code */ + taxCode?: Maybe<Scalars['String']> +} + +/** The response from the `createTaxRate` mutation */ +export type CreateTaxRatePayload = { + __typename?: 'CreateTaxRatePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The created tax rate */ + taxRate: TaxRate +} + +export type CreateUserInput = { + username?: Maybe<Scalars['String']> + email?: Maybe<Scalars['String']> + password?: Maybe<Scalars['String']> +} + +export type CreateUserResult = { + __typename?: 'CreateUserResult' + userId?: Maybe<Scalars['ID']> + loginResult?: Maybe<LoginResult> +} + +/** Input for the createdAt database field */ +export type CreatedAtInput = { + /** Start date, inclusive */ + gte?: Maybe<Scalars['DateTime']> + /** End date, inclusive */ + lte?: Maybe<Scalars['DateTime']> +} + +/** Represents one type of currency */ +export type Currency = Node & { + __typename?: 'Currency' + /** ID */ + _id: Scalars['ID'] + /** Currency code */ + code: Scalars['String'] + /** Decimal symbol */ + decimal?: Maybe<Scalars['String']> + /** Format string */ + format: Scalars['String'] + /** Exchange rate from shop default currency, if known */ + rate?: Maybe<Scalars['Float']> + /** The decimal scale used by this currency */ + scale?: Maybe<Scalars['Int']> + /** Currency symbol */ + symbol: Scalars['String'] + /** Thousands separator symbol */ + thousand?: Maybe<Scalars['String']> +} + +/** The product price or price range for a specific currency */ +export type CurrencyExchangeProductPricingInfo = { + __typename?: 'CurrencyExchangeProductPricingInfo' + /** + * A comparison price value, usually MSRP. If `price` is null, this will also be null. That is, + * only purchasable variants will have a `compareAtPrice`. + */ + compareAtPrice?: Maybe<Money> + /** The code for the currency these pricing details applies to */ + currency: Currency + /** + * UI should display this price. If a product has multiple potential prices depending on selected + * variants and options, then this is a price range string such as "$3.95 - $6.99". It includes the currency + * symbols. + */ + displayPrice: Scalars['String'] + /** The price of the most expensive possible variant+option combination */ + maxPrice: Scalars['Float'] + /** The price of the least expensive possible variant+option combination */ + minPrice: Scalars['Float'] + /** + * For variants with no options and for options, this will always be set to a price. For variants + * with options and products, this will be `null`. There must be a price for a variant to be + * added to a cart or purchased. Otherwise you would instead add one of its child options to a cart. + */ + price?: Maybe<Scalars['Float']> +} + +/** Represents Mongo Database information */ +export type DatabaseInformation = { + __typename?: 'DatabaseInformation' + /** Version of database */ + version: Scalars['String'] +} + +/** Objects implementing the Deletable support soft deletion */ +export type Deletable = { + /** + * If true, this object should be considered deleted. Soft deleted objects are not + * returned in query results unless you explicitly ask for them. + */ + isDeleted: Scalars['Boolean'] +} + +/** Input for the `deleteAddressValidationRule` mutation */ +export type DeleteAddressValidationRuleInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of the rule you want to delete */ + ruleId: Scalars['ID'] + /** Shop ID of the rule you want to delete */ + shopId: Scalars['ID'] +} + +/** Payload for the `deleteAddressValidationRule` mutation */ +export type DeleteAddressValidationRulePayload = { + __typename?: 'DeleteAddressValidationRulePayload' + /** Deleted address validation rule */ + addressValidationRule: AddressValidationRule + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Describes the input for removing a discount code */ +export type DeleteDiscountCodeInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The discount code ID */ + discountCodeId: Scalars['ID'] + /** Shop ID */ + shopId: Scalars['ID'] +} + +/** The response from the `deleteDiscountCode` mutation */ +export type DeleteDiscountCodePayload = { + __typename?: 'DeleteDiscountCodePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The deleted discount code */ + discountCode?: Maybe<DiscountCode> +} + +/** Input for the `deleteFlatRateFulfillmentMethod` mutation */ +export type DeleteFlatRateFulfillmentMethodInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the flat rate fulfillment method you want to delete */ + methodId: Scalars['ID'] + /** The shop that owns the method */ + shopId: Scalars['ID'] +} + +/** Response from the `deleteFlatRateFulfillmentMethod` mutation */ +export type DeleteFlatRateFulfillmentMethodPayload = { + __typename?: 'DeleteFlatRateFulfillmentMethodPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The removed fulfillment method */ + method: FlatRateFulfillmentMethod +} + +/** Input for the `deleteFlatRateFulfillmentRestriction` mutation */ +export type DeleteFlatRateFulfillmentRestrictionInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the flat rate fulfillment method restriction you want to delete */ + restrictionId: Scalars['ID'] + /** The shop that owns the flat rate fulfillment method restriction */ + shopId: Scalars['ID'] +} + +/** Response from the `deleteFlatRateFulfillmentRestriction` mutation */ +export type DeleteFlatRateFulfillmentRestrictionPayload = { + __typename?: 'DeleteFlatRateFulfillmentRestrictionPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The removed flat rate fulfillment method restriction */ + restriction: FlatRateFulfillmentRestriction +} + +/** Input for the deleteMediaRecord mutation */ +export type DeleteMediaRecordInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of MediaRecord to delete */ + mediaRecordId: Scalars['ID'] + /** ID of shop that owns this MediaRecord */ + shopId: Scalars['ID'] +} + +/** Response payload for the deleteMediaRecord mutation */ +export type DeleteMediaRecordPayload = { + __typename?: 'DeleteMediaRecordPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The deleted MediaRecord */ + mediaRecord: MediaRecord +} + +/** Input for the `deleteNavigationItem` mutation */ +export type DeleteNavigationItemInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the navigation item to delete */ + id: Scalars['ID'] + /** The ID of the shop navigation item belongs to */ + shopId: Scalars['ID'] +} + +/** Response payload for the `deleteNavigationItem` mutation */ +export type DeleteNavigationItemPayload = { + __typename?: 'DeleteNavigationItemPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The deleted navigation item */ + navigationItem?: Maybe<NavigationItem> +} + +/** Input for the `deleteSurcharge` mutation */ +export type DeleteSurchargeInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The shop that owns the method */ + shopId: Scalars['ID'] + /** The ID of the flat rate fulfillment method you want to delete */ + surchargeId: Scalars['ID'] +} + +/** Response from the `deleteSurcharge` mutation */ +export type DeleteSurchargePayload = { + __typename?: 'DeleteSurchargePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The removed fulfillment method */ + surcharge: Surcharge +} + +/** Describes the input for removing a tax rate */ +export type DeleteTaxRateInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Shop ID */ + shopId: Scalars['ID'] + /** The tax rate ID */ + taxRateId: Scalars['ID'] +} + +/** The response from the `deleteTaxRate` mutation */ +export type DeleteTaxRatePayload = { + __typename?: 'DeleteTaxRatePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The deleted tax rate */ + taxRate: TaxRate +} + +/** + * Destination restriction conditions. If multiple of `country`, + * `region`, and `postal` are set, there is an AND relationship. + */ +export type DestinationRestrictions = { + __typename?: 'DestinationRestrictions' + /** Restrict for any of these destination countries */ + country?: Maybe<Array<Maybe<Scalars['String']>>> + /** Restrict for any of these destination postal codes */ + postal?: Maybe<Array<Maybe<Scalars['String']>>> + /** Restrict for any of these destination regions */ + region?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** Input for a destination restriction condition */ +export type DestinationRestrictionsInput = { + /** Restrict for any of these destination countries */ + country?: Maybe<Array<Maybe<Scalars['String']>>> + /** Restrict for any of these destination postal codes */ + postal?: Maybe<Array<Maybe<Scalars['String']>>> + /** Restrict for any of these destination regions */ + region?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** Discount code calculation */ +export type DiscountCalculation = { + __typename?: 'DiscountCalculation' + /** Discount code calculation method */ + method?: Maybe<DiscountCalculationMethod> +} + +/** Input type for discount calculation */ +export type DiscountCalculationInput = { + /** Discount code calculation method */ + method?: Maybe<DiscountCalculationMethod> +} + +/** Discount calculation types */ +export enum DiscountCalculationMethod { + /** Store credit */ + Credit = 'credit', + /** Discount of order */ + Discount = 'discount', + /** Sale on an item */ + Sale = 'sale', + /** Discount to shipping */ + Shipping = 'shipping', +} + +/** A discount code */ +export type DiscountCode = { + __typename?: 'DiscountCode' + /** Discount code ID */ + _id: Scalars['ID'] + /** How the discount should be applied */ + calculation?: Maybe<DiscountCalculation> + /** Discount Code */ + code: Scalars['String'] + /** Discount code conditions */ + conditions?: Maybe<DiscountConditions> + /** Description to describe the discount code */ + description?: Maybe<Scalars['String']> + /** + * Discount is allowed to be string or number. + * it's a formula value (could be shipping code) + */ + discount?: Maybe<Scalars['String']> + /** Discount method type */ + discountMethod?: Maybe<DiscountMethod> + /** Label to describe the code */ + label?: Maybe<Scalars['String']> + /** The shop to which this DiscountCode belongs to */ + shop: Shop + /** History of transactions */ + transactions?: Maybe<Array<Maybe<DiscountTransaction>>> +} + +/** + * Wraps a list of DiscountCode`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type DiscountCodeConnection = { + __typename?: 'DiscountCodeConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<DiscountCodeEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<DiscountCode>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `DiscountCode` object */ +export type DiscountCodeEdge = { + __typename?: 'DiscountCodeEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The discount code */ + node?: Maybe<DiscountCode> +} + +/** Input type for filters to be applied to an discount codes list */ +export type DiscountCodeFilterInput = { + /** Keywords typed by the user in the search input field */ + searchField?: Maybe<Scalars['String']> +} + +/** Input type for a discount code */ +export type DiscountCodeInput = { + /** How the discount should be applied */ + calculation?: Maybe<DiscountCalculationInput> + /** Discount Code */ + code: Scalars['String'] + /** Discount code conditions */ + conditions?: Maybe<DiscountConditionsInput> + /** Description to describe the discount code */ + description?: Maybe<Scalars['String']> + /** + * Discount is allowed to be string or number. + * it's a formula value (could be shipping code) + */ + discount?: Maybe<Scalars['String']> + /** Discount method type */ + discountMethod?: Maybe<DiscountMethod> + /** Label to describe the code */ + label?: Maybe<Scalars['String']> + /** History of transactions */ + transactions?: Maybe<Array<Maybe<DiscountTransactionInput>>> +} + +/** The conditions an order must meet for a discount code to be applied */ +export type DiscountConditionOrder = { + __typename?: 'DiscountConditionOrder' + /** Order date range end */ + endDate?: Maybe<Scalars['DateTime']> + /** Maximum order value */ + max?: Maybe<Scalars['Float']> + /** Minimum order value */ + min: Scalars['Float'] + /** Order date range start */ + startDate?: Maybe<Scalars['DateTime']> +} + +/** Discount order conditions input type */ +export type DiscountConditionOrderInput = { + /** Order date range end */ + endDate?: Maybe<Scalars['DateTime']> + /** Maximum order value */ + max?: Maybe<Scalars['Float']> + /** Minimum order value */ + min: Scalars['Float'] + /** Order date range start */ + startDate?: Maybe<Scalars['DateTime']> +} + +/** Conditions for a discount code to be applied */ +export type DiscountConditions = { + __typename?: 'DiscountConditions' + /** Account Limit */ + accountLimit?: Maybe<Scalars['Int']> + /** Audience that may apply this discount code */ + audience?: Maybe<Array<Maybe<Scalars['String']>>> + /** Is this discount code enabled */ + enabled: Scalars['Boolean'] + /** Order conditions */ + order?: Maybe<DiscountConditionOrder> + /** Permissions that may apply this discount code */ + permissions?: Maybe<Array<Maybe<Scalars['String']>>> + /** Products that may apply this discount code */ + products?: Maybe<Array<Maybe<Scalars['String']>>> + /** + * Number of times this code may be redeemed. + * Setting to 100 means the first 100 customers may apply this code. + * Setting this value to 0 will allow this code to be applied an infinite number of times. + */ + redemptionLimit?: Maybe<Scalars['Int']> + /** Tags that may be apply this discount code */ + tags?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** Discount conditions input type */ +export type DiscountConditionsInput = { + /** Account Limit */ + accountLimit?: Maybe<Scalars['Int']> + /** Audience that may apply this discount code */ + audience?: Maybe<Array<Maybe<Scalars['String']>>> + /** Is this discount code enabled */ + enabled: Scalars['Boolean'] + /** Order conditions */ + order?: Maybe<DiscountConditionOrderInput> + /** Permissions that may apply this discount code */ + permissions?: Maybe<Array<Maybe<Scalars['String']>>> + /** Products that may apply this discount code */ + products?: Maybe<Array<Maybe<Scalars['String']>>> + /** + * Number of times this code may be redeemed. + * Setting to 100 means the first 100 customers may apply this code. + * Setting this value to 0 will allow this code to be applied an infinite number of times. + */ + redemptionLimit?: Maybe<Scalars['Int']> + /** Tags that may be apply this discount code */ + tags?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** Discount method types */ +export enum DiscountMethod { + /** Code type */ + Code = 'code', + /** Rate type */ + Rate = 'rate', +} + +/** Transaction history for a discount code */ +export type DiscountTransaction = { + __typename?: 'DiscountTransaction' + /** Date the code was applied */ + appliedAt?: Maybe<Scalars['DateTime']> + /** Cart id */ + cartId: Scalars['String'] + /** User id */ + userId: Scalars['String'] +} + +/** Discount transation input type */ +export type DiscountTransactionInput = { + /** Date the code was applied */ + appliedAt?: Maybe<Scalars['DateTime']> + /** Cart id */ + cartId: Scalars['String'] + /** User id */ + userId: Scalars['String'] +} + +/** Distance units */ +export enum DistanceUnit { + /** Centimeter */ + Cm = 'cm', + /** Foot */ + Ft = 'ft', + /** Inch */ + In = 'in', +} + +export type EmailRecord = { + __typename?: 'EmailRecord' + address?: Maybe<Scalars['String']> + verified?: Maybe<Scalars['Boolean']> +} + +/** A confirmable email record */ +export type EmailRecordInput = { + /** The actual email address */ + address?: Maybe<Scalars['Email']> + /** The services provided by this address */ + provides?: Maybe<Scalars['String']> + /** Has this address been verified? */ + verified?: Maybe<Scalars['Boolean']> +} + +/** Input for the `enablePaymentMethodForShop` mutation */ +export type EnablePaymentMethodForShopInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** True to enable it or false to disable it */ + isEnabled: Scalars['Boolean'] + /** The name of the payment method to enable or disable */ + paymentMethodName: Scalars['String'] + /** The ID of the shop for which this payment method should be enabled or disabled */ + shopId: Scalars['ID'] +} + +/** Response payload for the `enablePaymentMethodForShop` mutation */ +export type EnablePaymentMethodForShopPayload = { + __typename?: 'EnablePaymentMethodForShopPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The full list of payment methods for the shop */ + paymentMethods: Array<Maybe<PaymentMethod>> +} + +/** Data for an example IOU payment */ +export type ExampleIouPaymentData = { + __typename?: 'ExampleIOUPaymentData' + /** The name of the IOU payer entered by the shopper */ + fullName: Scalars['String'] +} + +/** Data for an example IOU payment method */ +export type ExampleIouPaymentMethodData = { + __typename?: 'ExampleIOUPaymentMethodData' + /** Example */ + example: Scalars['String'] +} + +/** Do not use this */ +export type FakeData = { + __typename?: 'FakeData' + /** Do not use this */ + doNotUse?: Maybe<Scalars['String']> +} + +/** Defines a fulfillment method that has a fixed price. This type is provided by the `flat-rate` fulfillment plugin. */ +export type FlatRateFulfillmentMethod = Node & { + __typename?: 'FlatRateFulfillmentMethod' + /** The flat rate fulfillment method ID */ + _id: Scalars['ID'] + /** The cost of this fulfillment method to the shop, if you track this */ + cost?: Maybe<Scalars['Float']> + /** The fulfillment types for which this method may be used. For example, `shipping` or `digital`. */ + fulfillmentTypes: Array<Maybe<FulfillmentType>> + /** The group to which this method belongs */ + group: Scalars['String'] + /** A fixed price to charge for handling costs when this fulfillment method is selected for an order */ + handling: Scalars['Float'] + /** Include this as a fulfillment option shown to shoppers during checkout? */ + isEnabled: Scalars['Boolean'] + /** The name of this method, for display in the user interface */ + label: Scalars['String'] + /** The name of this method, a unique identifier */ + name: Scalars['String'] + /** A fixed price to charge for fulfillment costs when this fulfillment method is selected for an order */ + rate: Scalars['Float'] + /** The shop to which this fulfillment method belongs */ + shop: Shop +} + +/** + * Wraps a list of FlatRateFulfillmentMethods`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type FlatRateFulfillmentMethodConnection = { + __typename?: 'FlatRateFulfillmentMethodConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<FlatRateFulfillmentMethodEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<FlatRateFulfillmentMethod>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `FlatRateFulfillmentMethod` object */ +export type FlatRateFulfillmentMethodEdge = { + __typename?: 'FlatRateFulfillmentMethodEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The fulfillment method */ + node?: Maybe<FlatRateFulfillmentMethod> +} + +/** Defines a fulfillment method that has a fixed price. This type is provided by the `flat-rate` fulfillment plugin. */ +export type FlatRateFulfillmentMethodInput = { + /** The cost of this fulfillment method to the shop, if you track this */ + cost?: Maybe<Scalars['Float']> + /** The fulfillment types for which this method may be used. For example, `shipping` or `digital`. */ + fulfillmentTypes: Array<Maybe<FulfillmentType>> + /** The group to which this method belongs */ + group: Scalars['String'] + /** A fixed price to charge for handling costs when this fulfillment method is selected for an order */ + handling: Scalars['Float'] + /** Include this as a fulfillment option shown to shoppers during checkout? */ + isEnabled: Scalars['Boolean'] + /** The name of this method, for display in the user interface */ + label: Scalars['String'] + /** The name of this method, a unique identifier */ + name: Scalars['String'] + /** A fixed price to charge for fulfillment costs when this fulfillment method is selected for an order */ + rate: Scalars['Float'] +} + +/** Defines a flat rate fulfillment method restriction. */ +export type FlatRateFulfillmentRestriction = Node & { + __typename?: 'FlatRateFulfillmentRestriction' + /** The restriction ID. */ + _id: Scalars['ID'] + /** Attribute restrictions. Multiple attribute restrictions are evaluated with AND. If both destination and attribute restrictions are present, they evaluate with AND. */ + attributes?: Maybe<Array<Maybe<AttributeRestrictions>>> + /** Destination restrictions. If multiple destination restrictions are present, the most localized is the only one evaluated (i.e. evaluate postal if present, then region if present, then country). If both destination and attribute restrictions are present, they evaluate with AND. */ + destination?: Maybe<DestinationRestrictions> + /** Method IDs to apply this restriction to. If none, applies to all methods as a universal restriction. */ + methodIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** The shop ID */ + shopId: Scalars['ID'] + /** The type of this restriction. Allowed types are `allow` or `deny`. */ + type: RestrictionTypeEnum +} + +/** + * Wraps a list of `FlatRateFulfillmentRestriction`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type FlatRateFulfillmentRestrictionConnection = { + __typename?: 'FlatRateFulfillmentRestrictionConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<FlatRateFulfillmentRestrictionEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<FlatRateFulfillmentRestriction>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `FlatRateFulfillmentRestriction` object */ +export type FlatRateFulfillmentRestrictionEdge = { + __typename?: 'FlatRateFulfillmentRestrictionEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The flat rate fulfillment restriction */ + node?: Maybe<FlatRateFulfillmentRestriction> +} + +/** Defines the input for a flat rate fulfillment method restriction. */ +export type FlatRateFulfillmentRestrictionInput = { + /** Attribute restrictions. Multiple attribute restrictions are evaluated with AND. If both destination and attribute restrictions are present, they evaluate with AND. */ + attributes?: Maybe<Array<Maybe<AttributeRestrictionsInput>>> + /** Destination restrictions. If multiple destination restrictions are present, the most localized is the only one evaluated (i.e. evaluate postal if present, then region if present, then country). If both destination and attribute restrictions are present, they evaluate with AND. */ + destination?: Maybe<DestinationRestrictionsInput> + /** Method IDs to apply this restriction to. If none, applies to all methods as a universal restriction. */ + methodIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** The type of this restriction. Allowed types are `allow` or `deny`. */ + type: RestrictionTypeEnum +} + +/** Allowed values for `FlatRateFulfillmentRestriction` sortBy parameter */ +export enum FlatRateFulfillmentRestrictionSortByField { + /** Date the restriction was created */ + CreatedAt = 'createdAt', +} + +/** Information needed by the selected fulfillment method to properly fulfill the order */ +export type FulfillmentData = { + __typename?: 'FulfillmentData' + /** The mailing address to which this fulfillment group should be shipped */ + shippingAddress?: Maybe<Address> +} + +/** + * Links one or more cart items to fulfillment data. The most common example is having one FulfillmentGroup + * per shipping address. + */ +export type FulfillmentGroup = Node & { + __typename?: 'FulfillmentGroup' + /** The fulfillment ID */ + _id: Scalars['ID'] + /** + * The list of fulfillment options from which the shopper may choose. This list is created by taking + * the full list of registered fulfillment methods, keeping only those that match the fulfillment `type` + * of this group, and then calculating a price and handlingPrice for each based on the `items` in this group. + */ + availableFulfillmentOptions: Array<Maybe<FulfillmentOption>> + /** Information needed by the fulfillment type to properly fulfill the order */ + data?: Maybe<FulfillmentData> + /** The items that are included in this fulfillment group */ + items: Array<Maybe<CartItem>> + /** The fulfillment method selected by a shopper for this group, with its associated price */ + selectedFulfillmentOption?: Maybe<FulfillmentOption> + /** The shipping address collected for this group, if relevant */ + shippingAddress?: Maybe<Address> + /** The shop that owns the items in this group and is responsible for fulfillment */ + shop: Shop + /** The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital` */ + type: FulfillmentType +} + +/** + * A single fulfillment method. Fulfillment methods are shown to shoppers along with a quote for them, + * and the shopper chooses one method per fulfillment group per cart during checkout. + */ +export type FulfillmentMethod = Node & { + __typename?: 'FulfillmentMethod' + /** The fulfillment method ID */ + _id: Scalars['ID'] + /** A carrier name */ + carrier?: Maybe<Scalars['String']> + /** The name of this method, for display in the user interface */ + displayName: Scalars['String'] + /** The fulfillment types for which this method may be used. For example, `shipping` or `digital`. */ + fulfillmentTypes: Array<Maybe<FulfillmentType>> + /** The group to which this method belongs */ + group?: Maybe<Scalars['String']> + /** The name of this method, a unique identifier */ + name: Scalars['String'] +} + +/** A fulfillment option for a cart fulfillment group, which is a method with an associated price */ +export type FulfillmentOption = { + __typename?: 'FulfillmentOption' + /** The fulfillment method this pricing is for */ + fulfillmentMethod?: Maybe<FulfillmentMethod> + /** The additional amount charged for handling */ + handlingPrice: Money + /** The base price charged */ + price: Money +} + +/** Allowed fulfillment types */ +export enum FulfillmentType { + /** An order will be fulfilled digitally, such as by sending a download link */ + Digital = 'digital', + /** An order will be fulfilled by the customer picking it up */ + Pickup = 'pickup', + /** An order will be fulfilled by the seller shipping it to the customer */ + Shipping = 'shipping', +} + +/** Input for the `generateSitemaps` mutation */ +export type GenerateSitemapsInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the shop to generate sitemap for */ + shopId: Scalars['ID'] +} + +/** Response for the `generateSitemaps` mutation */ +export type GenerateSitemapsPayload = { + __typename?: 'GenerateSitemapsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Whether the sitemap generation job was successfully scheduled */ + wasJobScheduled: Scalars['Boolean'] +} + +/** + * App settings that are not shop specific. Plugins extend the GlobalSettings type to support + * whatever settings they need. + */ +export type GlobalSettings = { + __typename?: 'GlobalSettings' + /** A fake setting necessary until some plugin extends this with a real setting */ + doNotUse?: Maybe<Scalars['String']> +} + +/** + * Updates for app settings that are not shop specific. Plugins extend + * this input type to support whatever settings they need. All fields + * must be optional. + */ +export type GlobalSettingsUpdates = { + /** Do not use this field */ + doNotUse?: Maybe<Scalars['String']> +} + +export type GrantOrRevokeAdminUiAccessInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The account ID to update */ + accountId: Scalars['String'] + /** The shop IDs to unassign or assign to the accounts */ + shopId: Scalars['String'] +} + +export type GrantOrRevokeAdminUiAccessPayload = { + __typename?: 'GrantOrRevokeAdminUIAccessPayload' + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The up to date account object */ + account?: Maybe<Account> +} + +/** Represents an account group */ +export type Group = Node & { + __typename?: 'Group' + /** The group ID */ + _id: Scalars['ID'] + /** The date and time at which this group was created */ + createdAt: Scalars['DateTime'] + /** The account that created this group */ + createdBy?: Maybe<Account> + /** A free text description of this group */ + description?: Maybe<Scalars['String']> + /** A unique name for the group */ + name: Scalars['String'] + /** The shop to which this group belongs */ + shop?: Maybe<Shop> + /** A unique URL-safe string representing this group */ + slug: Scalars['String'] + /** The date and time at which this group was last updated */ + updatedAt: Scalars['DateTime'] + /** A list of the account permissions implied by membership in this group */ + permissions?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** + * Wraps a list of `Groups`, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type GroupConnection = { + __typename?: 'GroupConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<GroupEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Group>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `Group` object */ +export type GroupEdge = NodeEdge & { + __typename?: 'GroupEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The group */ + node?: Maybe<Group> +} + +/** A group definition */ +export type GroupInput = { + /** A free text description of this group */ + description?: Maybe<Scalars['String']> + /** A unique name for the group */ + name: Scalars['String'] + /** A unique URL-safe string representing this group */ + slug?: Maybe<Scalars['String']> + /** A list of the account permissions implied by membership in this group */ + permissions?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** The fields by which you are allowed to sort any query that returns an `GroupConnection` */ +export enum GroupSortByField { + /** Group ID */ + Id = '_id', + /** Date and time at which this group was created */ + CreatedAt = 'createdAt', + /** Group name */ + Name = 'name', + /** Date and time at which this group was last updated */ + UpdatedAt = 'updatedAt', +} + +/** Information about an image */ +export type ImageInfo = { + __typename?: 'ImageInfo' + /** A list of URLs for various size files of this image */ + URLs?: Maybe<ImageSizes> + /** ID */ + _id?: Maybe<Scalars['ID']> + /** + * Sort by priority ascending when displaying more than one image for a product in a user interface. + * This is an integer with 1 being the first / highest priority image. + */ + priority?: Maybe<Scalars['Int']> + /** The related product ID */ + productId?: Maybe<Scalars['ID']> + /** The related variant ID, if linked with a particular variant */ + variantId?: Maybe<Scalars['ID']> +} + +/** A list of URLs for various sizes of an image */ +export type ImageSizes = { + __typename?: 'ImageSizes' + /** Use this URL to get a large resolution file for this image */ + large?: Maybe<Scalars['String']> + /** Use this URL to get a medium resolution file for this image */ + medium?: Maybe<Scalars['String']> + /** + * Use this URL to get this image with its original resolution as uploaded. This may not be + * the true original size if there is a hard cap on how big image files can be. + */ + original?: Maybe<Scalars['String']> + /** Use this URL to get a small resolution file for this image */ + small?: Maybe<Scalars['String']> + /** Use this URL to get a thumbnail resolution file for this image */ + thumbnail?: Maybe<Scalars['String']> +} + +export type ImpersonateReturn = { + __typename?: 'ImpersonateReturn' + authorized?: Maybe<Scalars['Boolean']> + tokens?: Maybe<Tokens> + user?: Maybe<User> +} + +export type ImpersonationUserIdentityInput = { + userId?: Maybe<Scalars['String']> + username?: Maybe<Scalars['String']> + email?: Maybe<Scalars['String']> +} + +/** Details about a CartItemInput that failed to be added to a cart due to a price mismatch */ +export type IncorrectPriceFailureDetails = { + __typename?: 'IncorrectPriceFailureDetails' + /** The current price in the system for this product configuration in the requested currency */ + currentPrice: Money + /** The productConfiguration that was provided with the CartItemInput that caused this failure */ + productConfiguration: ProductConfiguration + /** The price that was provided with the CartItemInput that caused this failure */ + providedPrice: Money +} + +/** Represents a single staff member invitation */ +export type Invitation = Node & { + __typename?: 'Invitation' + /** The invitation ID */ + _id: Scalars['ID'] + /** The e-mail address the invitation was sent to */ + email: Scalars['String'] + /** The groups this person was invited to */ + groups: Array<Maybe<Group>> + /** The shop this person was invited to. Optional because we can also invite merchants to create their own shops. */ + shop?: Maybe<Shop> + /** The admin who invited this person */ + invitedBy?: Maybe<Account> +} + +/** + * Wraps a list of `Invitation`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type InvitationConnection = { + __typename?: 'InvitationConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<InvitationEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Invitation>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is an `Invitation` object */ +export type InvitationEdge = NodeEdge & { + __typename?: 'InvitationEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The account */ + node?: Maybe<Invitation> +} + +/** Input parameters for the inviteShopMember mutation */ +export type InviteShopMemberInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The email address of the person to invite */ + email: Scalars['String'] + /** The permission group for this person's new account. DEPRECATED. Use `groupIds` field instead. */ + groupId?: Maybe<Scalars['ID']> + /** The permission groups for this person's new account */ + groupIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** The invitee's full name */ + name: Scalars['String'] + /** The ID of the shop to which you want to invite this person */ + shopId: Scalars['ID'] + /** Whether the newly invited user should get admin UI access to the shop upon sign-up */ + shouldGetAdminUIAccess?: Maybe<Scalars['Boolean']> +} + +/** The response from the `inviteShopMember` mutation */ +export type InviteShopMemberPayload = { + __typename?: 'InviteShopMemberPayload' + /** The account that was successfully created or found and updated by inviting this shop member */ + account?: Maybe<Account> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +export type LoginResult = { + __typename?: 'LoginResult' + sessionId?: Maybe<Scalars['String']> + tokens?: Maybe<Tokens> + user?: Maybe<User> +} + +/** Mass units */ +export enum MassUnit { + /** Gram */ + G = 'g', + /** Kilogram */ + Kg = 'kg', + /** Pound */ + Lb = 'lb', + /** Ounce */ + Oz = 'oz', +} + +/** A FileRecord for a media file */ +export type MediaRecord = { + __typename?: 'MediaRecord' + /** MediaRecord ID */ + _id: Scalars['ID'] + /** Custom metadata for the media record */ + metadata: MediaRecordMetadata + /** Core info about the original uploaded file */ + original: MediaRecordInfo +} + +/** Core info about the original uploaded media file */ +export type MediaRecordInfo = { + __typename?: 'MediaRecordInfo' + /** File name */ + name: Scalars['String'] + /** File size */ + size: Scalars['Int'] + /** File type */ + type: Scalars['String'] + /** Date and time at which the file was last updated */ + updatedAt: Scalars['DateTime'] + /** Date and time at which the file was uploaded */ + uploadedAt: Scalars['DateTime'] +} + +/** Core info about the original uploaded media file */ +export type MediaRecordInfoInput = { + /** File name */ + name: Scalars['String'] + /** File size */ + size: Scalars['Int'] + /** ID of the file uploaded to temporary storage */ + tempStoreId: Scalars['String'] + /** File type */ + type: Scalars['String'] + /** Date and time at which the file was last updated */ + updatedAt: Scalars['DateTime'] + /** Date and time at which the file was uploaded */ + uploadedAt: Scalars['DateTime'] +} + +/** A FileRecord for a media file */ +export type MediaRecordInput = { + /** Custom metadata for the media record */ + metadata: MediaRecordMetadataInput + /** Core info about the original uploaded file */ + original: MediaRecordInfoInput +} + +/** Custom metadata for the media record */ +export type MediaRecordMetadata = { + __typename?: 'MediaRecordMetadata' + /** True if the MediaRecord is archived. This typically means that the media will not show in a storefront but the image file data still exists. */ + isArchived: Scalars['Boolean'] + /** ID of the account that uploaded the file */ + ownerId?: Maybe<Scalars['String']> + /** Priority among media files with similar metadata */ + priority?: Maybe<Scalars['Int']> + /** ID of the related product, if the media is for a product */ + productId?: Maybe<Scalars['String']> + /** ID of the shop that owns the media */ + shopId: Scalars['String'] + /** A string that identifies where this media will be used, for filtering */ + type?: Maybe<Scalars['String']> + /** ID of the related product variant, if the media is for a product variant */ + variantId?: Maybe<Scalars['String']> +} + +/** Custom metadata for the media record */ +export type MediaRecordMetadataInput = { + /** Priority among media files with similar metadata */ + priority?: Maybe<Scalars['Int']> + /** ID of the related product, if the media is for a product */ + productId?: Maybe<Scalars['ID']> + /** A string that identifies where this media will be used, for filtering */ + type?: Maybe<Scalars['String']> + /** ID of the related product variant, if the media is for a product variant */ + variantId?: Maybe<Scalars['ID']> +} + +/** Input to add a surcharge message with language */ +export type MessagesByLanguageInput = { + /** The message for this language */ + content: Scalars['String'] + /** The language code */ + language: Scalars['String'] +} + +/** User defined attributes */ +export type Metafield = { + __typename?: 'Metafield' + /** Field description */ + description?: Maybe<Scalars['String']> + /** Field key */ + key?: Maybe<Scalars['String']> + /** Field namespace */ + namespace?: Maybe<Scalars['String']> + /** Field scope */ + scope?: Maybe<Scalars['String']> + /** Field value */ + value?: Maybe<Scalars['String']> + /** Field value type */ + valueType?: Maybe<Scalars['String']> +} + +/** User defined attributes. You can include only `key` and use these like tags, or also include a `value`. */ +export type MetafieldInput = { + /** Field description */ + description?: Maybe<Scalars['String']> + /** Field key */ + key: Scalars['String'] + /** Field namespace */ + namespace?: Maybe<Scalars['String']> + /** Field scope */ + scope?: Maybe<Scalars['String']> + /** Field value */ + value?: Maybe<Scalars['String']> + /** Field value type */ + valueType?: Maybe<Scalars['String']> +} + +/** Details about a CartItemInput that failed to be added to a cart due to a quantity error */ +export type MinOrderQuantityFailureDetails = { + __typename?: 'MinOrderQuantityFailureDetails' + /** The minimum quantity that can be added to a cart */ + minOrderQuantity: Scalars['Int'] + /** The productConfiguration that was provided with the CartItemInput that caused this failure */ + productConfiguration: ProductConfiguration + /** The quantity that was provided with the CartItemInput that caused this failure */ + quantity: Scalars['Int'] +} + +/** Represents some amount of a single currency */ +export type Money = { + __typename?: 'Money' + /** The numeric amount */ + amount: Scalars['Float'] + /** The currency, for interpreting the `amount` */ + currency: Currency + /** The display amount, with any currency symbols and decimal places already added */ + displayAmount: Scalars['String'] +} + +/** Represents input for some amount of a single currency */ +export type MoneyInput = { + /** The numeric amount */ + amount: Scalars['Float'] + /** The currency code, for interpreting the `amount` */ + currencyCode: Scalars['String'] +} + +/** Input for the moveOrderItems mutation */ +export type MoveOrderItemsInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the order fulfillment group from which all the items are to be moved. */ + fromFulfillmentGroupId: Scalars['ID'] + /** The list of item IDs to move. The full quantity must be moved. */ + itemIds: Array<Maybe<Scalars['ID']>> + /** ID of the order that has the items you want to move */ + orderId: Scalars['ID'] + /** The ID of the order fulfillment group to which all the items are to be moved. */ + toFulfillmentGroupId: Scalars['ID'] +} + +/** Response payload for the moveOrderItems mutation */ +export type MoveOrderItemsPayload = { + __typename?: 'MoveOrderItemsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated order */ + order: Order +} + +export type Mutation = { + __typename?: 'Mutation' + /** A test mutation that returns whatever string you send it */ + echo?: Maybe<Scalars['String']> + /** Archive a MediaRecord to hide it without deleting the backing file data */ + archiveMediaRecord: ArchiveMediaRecordPayload + /** Create the MediaRecord for file data after you upload it */ + createMediaRecord: CreateMediaRecordPayload + /** Delete a MediaRecord to delete both the record and the backing file data */ + deleteMediaRecord: DeleteMediaRecordPayload + /** Update the priority metadata for a MediaRecord. Used for sorting product and variant media in the catalog. */ + updateMediaRecordPriority: UpdateMediaRecordPriorityPayload + /** Create a new shop */ + createShop: CreateShopPayload + /** Given shop data, update the Shops collection with this data */ + updateShop: UpdateShopPayload + /** + * Returns app settings that are not shop specific. Plugins extend the GlobalSettings type to support + * whatever settings they need. + */ + updateGlobalSettings: UpdateGlobalSettingsPayload + /** + * Returns app settings for a specific shop. Plugins extend the ShopSettings type to support + * whatever settings they need. + */ + updateShopSettings: UpdateShopSettingsPayload + /** Retry a failed or cancelled email job */ + retryFailedEmail: RetryFailedEmailPayload + /** Create an address validation rule */ + createAddressValidationRule: CreateAddressValidationRulePayload + /** Delete an address validation rule */ + deleteAddressValidationRule: DeleteAddressValidationRulePayload + /** Update an address validation rule */ + updateAddressValidationRule: UpdateAddressValidationRulePayload + /** Use this mutation to verify the SMTP email settings */ + verifySMTPEmailSettings: VerifySmtpEmailSettingsInputPayload + /** Updates an existing template */ + updateTemplate: UpdateTemplatePayload + /** Add a new address to the `addressBook` field for an account */ + addAccountAddressBookEntry?: Maybe<AddAccountAddressBookEntryPayload> + /** Add an email address to an account */ + addAccountEmailRecord?: Maybe<AddAccountEmailRecordPayload> + /** Create an account based off a user */ + createAccount?: Maybe<CreateAccountPayload> + /** Remove an address from the `addressBook` field for an account */ + removeAccountAddressBookEntry?: Maybe<RemoveAccountAddressBookEntryPayload> + /** Remove an email address from an account */ + removeAccountEmailRecord?: Maybe<RemoveAccountEmailRecordPayload> + /** Send a reset password email to an email address from an account */ + sendResetAccountPasswordEmail?: Maybe<SendResetAccountPasswordEmailPayload> + /** Set default email address for an account */ + setAccountDefaultEmail?: Maybe<SetAccountDefaultEmailPayload> + /** Remove an address that exists in the `addressBook` field for an account */ + updateAccountAddressBookEntry?: Maybe<UpdateAccountAddressBookEntryPayload> + /** Update account fields */ + updateAccount?: Maybe<UpdateAccountPayload> + /** Bulk-update groups for accounts */ + updateGroupsForAccounts?: Maybe<UpdateGroupsForAccountsPayload> + /** Grant admin UI access for shops to a specific users */ + grantAdminUIAccess: GrantOrRevokeAdminUiAccessPayload + /** Revoke admin UI access to shops for specific users */ + revokeAdminUIAccess: GrantOrRevokeAdminUiAccessPayload + /** Update admin UI access to shops for specific users */ + updateAdminUIAccess: UpdateAdminUiAccessPayload + /** Add an account to a group */ + addAccountToGroup?: Maybe<AddAccountToGroupPayload> + /** Create a new account group. These are usually used for account permissions */ + createAccountGroup?: Maybe<CreateAccountGroupPayload> + /** Remove an account from a group */ + removeAccountFromGroup?: Maybe<RemoveAccountFromGroupPayload> + /** Remove an existing account group */ + removeAccountGroup?: Maybe<RemoveAccountGroupPayload> + /** Update an existing account group */ + updateAccountGroup?: Maybe<UpdateAccountGroupPayload> + /** + * Given a person's email address and name, invite them to create an account for a certain shop, + * and put them in the provided permission group + */ + inviteShopMember?: Maybe<InviteShopMemberPayload> + /** Archive products */ + archiveProducts: ArchiveProductsPayload + /** Archive product variants */ + archiveProductVariants: ArchiveProductVariantsPayload + /** Update the isVisible property of an array of products */ + updateProductsVisibility: UpdateProductsVisibilityPayload + /** Create a new product */ + createProduct: CreateProductPayload + /** Create a new product variant */ + createProductVariant: CreateProductVariantPayload + /** Clone an existing product */ + cloneProducts: CloneProductsPayload + /** Clone an existing product variant */ + cloneProductVariants: CloneProductVariantsPayload + /** Update an existing product */ + updateProduct: UpdateProductPayload + /** Update an existing product variant */ + updateProductVariant: UpdateProductVariantPayload + /** Bulk operation for adding an array of tags to an array of products */ + addTagsToProducts: ProductTagsOperationPayload + /** Bulk operation for removing an array of tags from an array of products */ + removeTagsFromProducts: ProductTagsOperationPayload + /** Publish products to the Catalog collection by product ID */ + publishProductsToCatalog?: Maybe<Array<Maybe<CatalogItemProduct>>> + /** Adds a new tag */ + addTag: AddTagPayload + /** Removes an existing tag */ + removeTag: RemoveTagPayload + /** Add an image to the tag */ + setTagHeroMedia: SetTagHeroMediaPayload + /** Updates an existing tag */ + updateTag: UpdateTagPayload + /** Update an existing product variants prices */ + updateProductVariantPrices: UpdateProductVariantPricesPayload + /** Force recalculation of the system-managed `inventoryReserved` field based on current order statuses */ + recalculateReservedSimpleInventory: RecalculateReservedSimpleInventoryPayload + /** Update the SimpleInventory info for a product configuration */ + updateSimpleInventory: UpdateSimpleInventoryPayload + /** Add item(s) to a cart */ + addCartItems: AddCartItemsPayload + /** Create a new cart */ + createCart: CreateCartPayload + /** Reconcile an anonymous cart with the current account cart for the same shop */ + reconcileCarts: ReconcileCartsPayload + /** Remove item(s) from a cart */ + removeCartItems: RemoveCartItemsPayload + /** Set the email address for an anonymous cart */ + setEmailOnAnonymousCart: SetEmailOnAnonymousCartPayload + /** Update cart item(s) quantity. Use absolute quantity. If updating to 0, the item will be removed. */ + updateCartItemsQuantity: UpdateCartItemsQuantityPayload + /** Select a fulfillment option from the `availableFulfillmentOptions` list for a fulfillment group */ + selectFulfillmentOptionForGroup: SelectFulfillmentOptionForGroupPayload + /** Set the shipping address for all fulfillment groups */ + setShippingAddressOnCart: SetShippingAddressOnCartPayload + /** + * Clients should call this as necessary during checkout to update the `availableFulfillmentOptions` + * property for all fulfillment groups of the cart with fresh price quotes. These need to be + * recalculated every time the items in that group change. When the order is placed, the chosen + * option for each group will have its prices recalculated one last time. If the prices do not match, + * order creation will fail. + */ + updateFulfillmentOptionsForGroup: UpdateFulfillmentOptionsForGroupPayload + /** + * Use this mutation to add a new order fulfillment group to an order. It must have at least one + * item. Items may be provided or moved from another existing group or both. + */ + addOrderFulfillmentGroup: AddOrderFulfillmentGroupPayload + /** + * Use this mutation to cancel one item of an order, either for the full ordered quantity + * or for a partial quantity. If partial, the item will be split into two items and the + * original item will have a lower quantity and will be canceled. + * + * If this results in all items in a fulfillment group being canceled, the group will also + * be canceled. If this results in all fulfillment groups being canceled, the full order will + * also be canceled. + */ + cancelOrderItem: CancelOrderItemPayload + /** Use this mutation to create a refund on a payment method used to make the order */ + createRefund: CreateRefundPayload + /** Use this mutation to move one or more items between existing order fulfillment groups. */ + moveOrderItems: MoveOrderItemsPayload + /** + * Use this mutation to place an order, providing information necessary to pay for it. + * The order will be placed only if authorization is successful for all submitted payments. + */ + placeOrder: PlaceOrderPayload + /** + * Use this mutation to reduce the quantity of one item of an order and create + * a new item for the remaining quantity in the same fulfillment group, and with the + * same item status. You may want to do this if you are only able to partially fulfill + * the item order right now. + */ + splitOrderItem: SplitOrderItemPayload + /** Use this mutation to update order details after the order has been placed. */ + updateOrder: UpdateOrderPayload + /** Use this mutation to update an order fulfillment group status and tracking information. */ + updateOrderFulfillmentGroup: UpdateOrderFulfillmentGroupPayload + /** Approve one or more payments for an order */ + approveOrderPayments: ApproveOrderPaymentsPayload + /** Capture one or more payments for an order */ + captureOrderPayments: CaptureOrderPaymentsPayload + /** Enable a payment method for a shop */ + enablePaymentMethodForShop: EnablePaymentMethodForShopPayload + /** Create a new discount code */ + createDiscountCode?: Maybe<CreateDiscountCodePayload> + /** Update a discount code */ + updateDiscountCode?: Maybe<UpdateDiscountCodePayload> + /** Delete a discount code */ + deleteDiscountCode?: Maybe<DeleteDiscountCodePayload> + /** Apply a discount code to a cart */ + applyDiscountCodeToCart: ApplyDiscountCodeToCartPayload + /** Remove a discount code from a cart */ + removeDiscountCodeFromCart: RemoveDiscountCodeFromCartPayload + /** Create a surcharge */ + createSurcharge: CreateSurchargePayload + /** Delete a flat rate fulfillment restriction */ + deleteSurcharge: DeleteSurchargePayload + /** Update a flat rate fulfillment surcharge */ + updateSurcharge: UpdateSurchargePayload + /** Create a flat rate fulfillment method */ + createFlatRateFulfillmentMethod: CreateFlatRateFulfillmentMethodPayload + /** Update a flat rate fulfillment method */ + updateFlatRateFulfillmentMethod: UpdateFlatRateFulfillmentMethodPayload + /** Delete a flat rate fulfillment method */ + deleteFlatRateFulfillmentMethod: DeleteFlatRateFulfillmentMethodPayload + /** Create a flat rate fulfillment method restriction. */ + createFlatRateFulfillmentRestriction: CreateFlatRateFulfillmentRestrictionPayload + /** Delete a flat rate fulfillment method restriction */ + deleteFlatRateFulfillmentRestriction: DeleteFlatRateFulfillmentRestrictionPayload + /** Update a flat rate fulfillment method restriction */ + updateFlatRateFulfillmentRestriction: UpdateFlatRateFulfillmentRestrictionPayload + /** Create a new tax rate */ + createTaxRate?: Maybe<CreateTaxRatePayload> + /** Update a tax rate */ + updateTaxRate?: Maybe<UpdateTaxRatePayload> + /** Delete a tax rate */ + deleteTaxRate?: Maybe<DeleteTaxRatePayload> + /** Create a new navigation item */ + createNavigationItem?: Maybe<CreateNavigationItemPayload> + /** Create a new navigation tree */ + createNavigationTree: CreateNavigationTreePayload + /** Delete a navigation item */ + deleteNavigationItem?: Maybe<DeleteNavigationItemPayload> + /** Publish the draft structure for a navigation tree and the draft changes for all of its navigation items. Sets hasUnpublishedChanges to false on tree and its items */ + publishNavigationChanges?: Maybe<PublishNavigationChangesPayload> + /** Update an existing navigation item's draft data. Sets hasUnpublishedChanges to true */ + updateNavigationItem?: Maybe<UpdateNavigationItemPayload> + /** Update an existing navigation tree's draft items. Sets hasUnpublishedChanges to true */ + updateNavigationTree?: Maybe<UpdateNavigationTreePayload> + /** Generate sitemap documents */ + generateSitemaps: GenerateSitemapsPayload + createUser?: Maybe<CreateUserResult> + verifyEmail?: Maybe<Scalars['Boolean']> + resetPassword?: Maybe<LoginResult> + sendVerificationEmail?: Maybe<Scalars['Boolean']> + sendResetPasswordEmail?: Maybe<Scalars['Boolean']> + addEmail?: Maybe<Scalars['Boolean']> + changePassword?: Maybe<Scalars['Boolean']> + twoFactorSet?: Maybe<Scalars['Boolean']> + twoFactorUnset?: Maybe<Scalars['Boolean']> + impersonate?: Maybe<ImpersonateReturn> + refreshTokens?: Maybe<LoginResult> + logout?: Maybe<Scalars['Boolean']> + authenticate?: Maybe<LoginResult> + verifyAuthentication?: Maybe<Scalars['Boolean']> +} + +export type MutationEchoArgs = { + str?: Maybe<Scalars['String']> +} + +export type MutationArchiveMediaRecordArgs = { + input: ArchiveMediaRecordInput +} + +export type MutationCreateMediaRecordArgs = { + input: CreateMediaRecordInput +} + +export type MutationDeleteMediaRecordArgs = { + input: DeleteMediaRecordInput +} + +export type MutationUpdateMediaRecordPriorityArgs = { + input: UpdateMediaRecordPriorityInput +} + +export type MutationCreateShopArgs = { + input: CreateShopInput +} + +export type MutationUpdateShopArgs = { + input: UpdateShopInput +} + +export type MutationUpdateGlobalSettingsArgs = { + input: UpdateGlobalSettingsInput +} + +export type MutationUpdateShopSettingsArgs = { + input: UpdateShopSettingsInput +} + +export type MutationRetryFailedEmailArgs = { + input: RetryFailedEmailInput +} + +export type MutationCreateAddressValidationRuleArgs = { + input: CreateAddressValidationRuleInput +} + +export type MutationDeleteAddressValidationRuleArgs = { + input: DeleteAddressValidationRuleInput +} + +export type MutationUpdateAddressValidationRuleArgs = { + input: UpdateAddressValidationRuleInput +} + +export type MutationVerifySmtpEmailSettingsArgs = { + input: VerifySmtpEmailSettingsInput +} + +export type MutationUpdateTemplateArgs = { + input: UpdateTemplateInput +} + +export type MutationAddAccountAddressBookEntryArgs = { + input: AddAccountAddressBookEntryInput +} + +export type MutationAddAccountEmailRecordArgs = { + input: AddAccountEmailRecordInput +} + +export type MutationCreateAccountArgs = { + input: CreateAccountInput +} + +export type MutationRemoveAccountAddressBookEntryArgs = { + input: RemoveAccountAddressBookEntryInput +} + +export type MutationRemoveAccountEmailRecordArgs = { + input: RemoveAccountEmailRecordInput +} + +export type MutationSendResetAccountPasswordEmailArgs = { + input: SendResetAccountPasswordEmailInput +} + +export type MutationSetAccountDefaultEmailArgs = { + input: SetAccountDefaultEmailInput +} + +export type MutationUpdateAccountAddressBookEntryArgs = { + input: UpdateAccountAddressBookEntryInput +} + +export type MutationUpdateAccountArgs = { + input: UpdateAccountInput +} + +export type MutationUpdateGroupsForAccountsArgs = { + input: UpdateGroupsForAccountsInput +} + +export type MutationGrantAdminUiAccessArgs = { + input: GrantOrRevokeAdminUiAccessInput +} + +export type MutationRevokeAdminUiAccessArgs = { + input: GrantOrRevokeAdminUiAccessInput +} + +export type MutationUpdateAdminUiAccessArgs = { + input: UpdateAdminUiAccessInput +} + +export type MutationAddAccountToGroupArgs = { + input: AddAccountToGroupInput +} + +export type MutationCreateAccountGroupArgs = { + input: CreateAccountGroupInput +} + +export type MutationRemoveAccountFromGroupArgs = { + input: RemoveAccountFromGroupInput +} + +export type MutationRemoveAccountGroupArgs = { + input: RemoveAccountGroupInput +} + +export type MutationUpdateAccountGroupArgs = { + input: UpdateAccountGroupInput +} + +export type MutationInviteShopMemberArgs = { + input: InviteShopMemberInput +} + +export type MutationArchiveProductsArgs = { + input: ArchiveProductsInput +} + +export type MutationArchiveProductVariantsArgs = { + input: ArchiveProductVariantsInput +} + +export type MutationUpdateProductsVisibilityArgs = { + input: UpdateProductsVisibilityInput +} + +export type MutationCreateProductArgs = { + input: CreateProductInput +} + +export type MutationCreateProductVariantArgs = { + input: CreateProductVariantInput +} + +export type MutationCloneProductsArgs = { + input: CloneProductsInput +} + +export type MutationCloneProductVariantsArgs = { + input: CloneProductVariantsInput +} + +export type MutationUpdateProductArgs = { + input: UpdateProductInput +} + +export type MutationUpdateProductVariantArgs = { + input: UpdateProductVariantInput +} + +export type MutationAddTagsToProductsArgs = { + input: ProductTagsOperationInput +} + +export type MutationRemoveTagsFromProductsArgs = { + input: ProductTagsOperationInput +} + +export type MutationPublishProductsToCatalogArgs = { + productIds: Array<Maybe<Scalars['ID']>> +} + +export type MutationAddTagArgs = { + input: AddTagInput +} + +export type MutationRemoveTagArgs = { + input: RemoveTagInput +} + +export type MutationSetTagHeroMediaArgs = { + input: SetTagHeroMediaInput +} + +export type MutationUpdateTagArgs = { + input: UpdateTagInput +} + +export type MutationUpdateProductVariantPricesArgs = { + input: UpdateProductVariantPricesInput +} + +export type MutationRecalculateReservedSimpleInventoryArgs = { + input: RecalculateReservedSimpleInventoryInput +} + +export type MutationUpdateSimpleInventoryArgs = { + input: UpdateSimpleInventoryInput +} + +export type MutationAddCartItemsArgs = { + input: AddCartItemsInput +} + +export type MutationCreateCartArgs = { + input: CreateCartInput +} + +export type MutationReconcileCartsArgs = { + input: ReconcileCartsInput +} + +export type MutationRemoveCartItemsArgs = { + input: RemoveCartItemsInput +} + +export type MutationSetEmailOnAnonymousCartArgs = { + input: SetEmailOnAnonymousCartInput +} + +export type MutationUpdateCartItemsQuantityArgs = { + input: UpdateCartItemsQuantityInput +} + +export type MutationSelectFulfillmentOptionForGroupArgs = { + input: SelectFulfillmentOptionForGroupInput +} + +export type MutationSetShippingAddressOnCartArgs = { + input: SetShippingAddressOnCartInput +} + +export type MutationUpdateFulfillmentOptionsForGroupArgs = { + input: UpdateFulfillmentOptionsForGroupInput +} + +export type MutationAddOrderFulfillmentGroupArgs = { + input: AddOrderFulfillmentGroupInput +} + +export type MutationCancelOrderItemArgs = { + input: CancelOrderItemInput +} + +export type MutationCreateRefundArgs = { + input: CreateRefundInput +} + +export type MutationMoveOrderItemsArgs = { + input: MoveOrderItemsInput +} + +export type MutationPlaceOrderArgs = { + input: PlaceOrderInput +} + +export type MutationSplitOrderItemArgs = { + input: SplitOrderItemInput +} + +export type MutationUpdateOrderArgs = { + input: UpdateOrderInput +} + +export type MutationUpdateOrderFulfillmentGroupArgs = { + input: UpdateOrderFulfillmentGroupInput +} + +export type MutationApproveOrderPaymentsArgs = { + input: ApproveOrderPaymentsInput +} + +export type MutationCaptureOrderPaymentsArgs = { + input: CaptureOrderPaymentsInput +} + +export type MutationEnablePaymentMethodForShopArgs = { + input: EnablePaymentMethodForShopInput +} + +export type MutationCreateDiscountCodeArgs = { + input: CreateDiscountCodeInput +} + +export type MutationUpdateDiscountCodeArgs = { + input: UpdateDiscountCodeInput +} + +export type MutationDeleteDiscountCodeArgs = { + input: DeleteDiscountCodeInput +} + +export type MutationApplyDiscountCodeToCartArgs = { + input: ApplyDiscountCodeToCartInput +} + +export type MutationRemoveDiscountCodeFromCartArgs = { + input: RemoveDiscountCodeFromCartInput +} + +export type MutationCreateSurchargeArgs = { + input: CreateSurchargeInput +} + +export type MutationDeleteSurchargeArgs = { + input: DeleteSurchargeInput +} + +export type MutationUpdateSurchargeArgs = { + input: UpdateSurchargeInput +} + +export type MutationCreateFlatRateFulfillmentMethodArgs = { + input: CreateFlatRateFulfillmentMethodInput +} + +export type MutationUpdateFlatRateFulfillmentMethodArgs = { + input: UpdateFlatRateFulfillmentMethodInput +} + +export type MutationDeleteFlatRateFulfillmentMethodArgs = { + input: DeleteFlatRateFulfillmentMethodInput +} + +export type MutationCreateFlatRateFulfillmentRestrictionArgs = { + input: CreateFlatRateFulfillmentRestrictionInput +} + +export type MutationDeleteFlatRateFulfillmentRestrictionArgs = { + input: DeleteFlatRateFulfillmentRestrictionInput +} + +export type MutationUpdateFlatRateFulfillmentRestrictionArgs = { + input: UpdateFlatRateFulfillmentRestrictionInput +} + +export type MutationCreateTaxRateArgs = { + input: CreateTaxRateInput +} + +export type MutationUpdateTaxRateArgs = { + input: UpdateTaxRateInput +} + +export type MutationDeleteTaxRateArgs = { + input: DeleteTaxRateInput +} + +export type MutationCreateNavigationItemArgs = { + input: CreateNavigationItemInput +} + +export type MutationCreateNavigationTreeArgs = { + input: CreateNavigationTreeInput +} + +export type MutationDeleteNavigationItemArgs = { + input: DeleteNavigationItemInput +} + +export type MutationPublishNavigationChangesArgs = { + input: PublishNavigationChangesInput +} + +export type MutationUpdateNavigationItemArgs = { + input: UpdateNavigationItemInput +} + +export type MutationUpdateNavigationTreeArgs = { + input: UpdateNavigationTreeInput +} + +export type MutationGenerateSitemapsArgs = { + input?: Maybe<GenerateSitemapsInput> +} + +export type MutationCreateUserArgs = { + user: CreateUserInput +} + +export type MutationVerifyEmailArgs = { + token: Scalars['String'] +} + +export type MutationResetPasswordArgs = { + token: Scalars['String'] + newPassword: Scalars['String'] +} + +export type MutationSendVerificationEmailArgs = { + email: Scalars['String'] +} + +export type MutationSendResetPasswordEmailArgs = { + email: Scalars['String'] +} + +export type MutationAddEmailArgs = { + newEmail: Scalars['String'] +} + +export type MutationChangePasswordArgs = { + oldPassword: Scalars['String'] + newPassword: Scalars['String'] +} + +export type MutationTwoFactorSetArgs = { + secret: TwoFactorSecretKeyInput + code: Scalars['String'] +} + +export type MutationTwoFactorUnsetArgs = { + code: Scalars['String'] +} + +export type MutationImpersonateArgs = { + accessToken: Scalars['String'] + impersonated: ImpersonationUserIdentityInput +} + +export type MutationRefreshTokensArgs = { + accessToken: Scalars['String'] + refreshToken: Scalars['String'] +} + +export type MutationAuthenticateArgs = { + serviceName: Scalars['String'] + params: AuthenticateParamsInput +} + +export type MutationVerifyAuthenticationArgs = { + serviceName: Scalars['String'] + params: AuthenticateParamsInput +} + +/** Represents a single navigation item */ +export type NavigationItem = Node & { + __typename?: 'NavigationItem' + /** The navigation item ID */ + _id: Scalars['ID'] + /** The date and time at which this navigation item was created */ + createdAt: Scalars['DateTime'] + /** The published data for this navigation item */ + data?: Maybe<NavigationItemData> + /** The draft/unpublished data for this navigation item */ + draftData?: Maybe<NavigationItemData> + /** Whether the navigation item has unpublished changes */ + hasUnpublishedChanges?: Maybe<Scalars['Boolean']> + /** An object storing additional metadata about the navigation item (such as its related tag) */ + metadata?: Maybe<Scalars['JSONObject']> + /** The ID of the shop the navigation item belongs to */ + shopId: Scalars['ID'] +} + +/** + * Wraps a list of `NavigationItem`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type NavigationItemConnection = { + __typename?: 'NavigationItemConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<NavigationItemEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<NavigationItem>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** Represents the translated content for a navigation item */ +export type NavigationItemContent = { + __typename?: 'NavigationItemContent' + /** The language of the piece of navigation content */ + language: Scalars['String'] + /** The translated value, in plain text or markdown */ + value?: Maybe<Scalars['String']> +} + +/** NavigationItem content input */ +export type NavigationItemContentInput = { + /** The language of the piece of navigation content */ + language: Scalars['String'] + /** The translated value, in plain text or markdown */ + value?: Maybe<Scalars['String']> +} + +/** Represents the data for a navigation item */ +export type NavigationItemData = { + __typename?: 'NavigationItemData' + /** CSS class names to add to the menu item for display */ + classNames?: Maybe<Scalars['String']> + /** The content for the navigation item, in one or more languages */ + content?: Maybe<Array<Maybe<NavigationItemContent>>> + /** The translated content for a navigation item */ + contentForLanguage?: Maybe<Scalars['String']> + /** Whether the provided URL is relative or external */ + isUrlRelative?: Maybe<Scalars['Boolean']> + /** Whether the navigation item should trigger a new tab/window to open when clicked */ + shouldOpenInNewWindow?: Maybe<Scalars['Boolean']> + /** The URL for the navigation item to link to */ + url?: Maybe<Scalars['String']> +} + +/** NavigationItemData input */ +export type NavigationItemDataInput = { + /** CSS class names to add to the menu item for display */ + classNames?: Maybe<Scalars['String']> + /** The content for the navigation item, in one or more languages */ + content?: Maybe<Array<Maybe<NavigationItemContentInput>>> + /** Whether the provided URL is relative or external */ + isUrlRelative?: Maybe<Scalars['Boolean']> + /** Whether the navigation item should trigger a new tab/window to open when clicked */ + shouldOpenInNewWindow?: Maybe<Scalars['Boolean']> + /** The URL for the navigation item to link to */ + url?: Maybe<Scalars['String']> +} + +/** A connection edge in which each node is a `NavigationItem` object */ +export type NavigationItemEdge = NodeEdge & { + __typename?: 'NavigationItemEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The navigation item */ + node?: Maybe<NavigationItem> +} + +/** NavigationItem input */ +export type NavigationItemInput = { + /** The draft/unpublished data for this navigation item */ + draftData?: Maybe<NavigationItemDataInput> + /** An object storing additional metadata about the navigation item (such as its related tag) */ + metadata?: Maybe<Scalars['JSONObject']> + /** Shop ID of the navigation item */ + shopId: Scalars['ID'] +} + +/** The fields by which you are allowed to sort any query that returns a `NavigationItemConnection` */ +export enum NavigationItemSortByField { + /** Sort by NavigationItem ID */ + Id = '_id', + /** Sort by when the NavigationItem was created */ + CreatedAt = 'createdAt', +} + +/** Represents a navigation tree containing multiple levels of navigation items */ +export type NavigationTree = Node & { + __typename?: 'NavigationTree' + /** The navigation tree ID */ + _id: Scalars['ID'] + /** The draft navigation items that make up this tree */ + draftItems?: Maybe<Array<Maybe<NavigationTreeItem>>> + /** Whether the navigation item has unpublished changes */ + hasUnpublishedChanges?: Maybe<Scalars['Boolean']> + /** The published navigation items that make up this tree */ + items?: Maybe<Array<Maybe<NavigationTreeItem>>> + /** The name of the tree, for operator display purposes. Assumed to be in the primary shop's language */ + name: Scalars['String'] + /** The ID of the shop this navigation tree belongs to */ + shopId: Scalars['ID'] +} + +/** NavigationTree input */ +export type NavigationTreeInput = { + /** The draft navigation items that make up this tree */ + draftItems?: Maybe<Array<Maybe<NavigationTreeItemInput>>> + /** The name of the tree, for operator display purposes */ + name?: Maybe<Scalars['String']> +} + +/** Represents a navigation item and its children in a tree */ +export type NavigationTreeItem = { + __typename?: 'NavigationTreeItem' + /** Whether the navigation item should display its children */ + expanded?: Maybe<Scalars['Boolean']> + /** Whether the navigation item should be hidden from customers */ + isPrivate?: Maybe<Scalars['Boolean']> + /** Whether the navigaton item is a secondary navigation item */ + isSecondary?: Maybe<Scalars['Boolean']> + /** Whether the navigation ttem should shown in query results for customers and admins */ + isVisible?: Maybe<Scalars['Boolean']> + /** The child navigation items */ + items?: Maybe<Array<Maybe<NavigationTreeItem>>> + /** The navigation item */ + navigationItem: NavigationItem +} + +/** NavigationTree item input */ +export type NavigationTreeItemInput = { + /** Whether the navigation item should display its children */ + expanded?: Maybe<Scalars['Boolean']> + /** Whether the navigation item should be hidden from customers */ + isPrivate?: Maybe<Scalars['Boolean']> + /** Whether the navigaton item is a secondary navigation item */ + isSecondary?: Maybe<Scalars['Boolean']> + /** Whether the navigation ttem should shown in query results for customers and admins */ + isVisible?: Maybe<Scalars['Boolean']> + /** The child navigation items */ + items?: Maybe<Array<Maybe<NavigationTreeItemInput>>> + /** The ID of the navigation item */ + navigationItemId: Scalars['ID'] +} + +/** Objects implementing the Node interface will always have an _id field that is globally unique. */ +export type Node = { + /** The ID of the object */ + _id: Scalars['ID'] +} + +/** + * Objects implementing the NodeEdge interface will always have a node and a cursor + * that represents that node for purposes of requesting paginated results. + */ +export type NodeEdge = { + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The node itself */ + node?: Maybe<Node> +} + +/** An order */ +export type Order = Node & { + __typename?: 'Order' + /** The Order ID */ + _id: Scalars['ID'] + /** The account that placed the order. Some orders are created for anonymous users. Anonymous orders have a null account. */ + account?: Maybe<Account> + /** The ID of the cart that created this order. Carts are deleted after becoming orders, so this is just a reference. */ + cartId?: Maybe<Scalars['ID']> + /** The date and time at which the cart was created, which is when the first item was added to it. */ + createdAt: Scalars['DateTime'] + /** The order status for display in UI */ + displayStatus: Scalars['String'] + /** An email address that has been associated with the cart */ + email?: Maybe<Scalars['String']> + /** One or more fulfillment groups. Each of these are fulfilled and charged as separate orders. */ + fulfillmentGroups: Array<Maybe<OrderFulfillmentGroup>> + /** Notes about the order. This will always return an array but it may be empty */ + notes: Array<Maybe<OrderNote>> + /** + * Payments that collectively have paid or will pay for the total amount due for this order. + * May be null if no payment is needed. + */ + payments?: Maybe<Array<Maybe<Payment>>> + /** + * An ID by which the customer can reference this order when enquiring about it. A storefront user + * interface may show this to customers. Do not display other IDs (`_id`) to customers. + */ + referenceId: Scalars['String'] + /** Refunds that have been applied to the payments on this order. */ + refunds?: Maybe<Array<Maybe<Refund>>> + /** The shop through which the order was placed */ + shop: Shop + /** The machine-readable order status. */ + status: Scalars['String'] + /** A summary of the totals for all fulfillment groups for this order */ + summary: OrderSummary + /** Total quantity of all items in the order */ + totalItemQuantity: Scalars['Int'] + /** The date and time at which this order was last updated */ + updatedAt: Scalars['DateTime'] + /** Surcharges applied to this order */ + surcharges: Array<Maybe<AppliedSurcharge>> +} + +/** An order */ +export type OrderDisplayStatusArgs = { + language: Scalars['String'] +} + +/** + * Wraps a list of `Order`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type OrderConnection = { + __typename?: 'OrderConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<OrderEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Order>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `Order` object */ +export type OrderEdge = NodeEdge & { + __typename?: 'OrderEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The order */ + node?: Maybe<Order> +} + +/** Input type for filters to by applied to an Orders list */ +export type OrderFilterInput = { + /** A createdAt date range to filter by */ + createdAt?: Maybe<CreatedAtInput> + /** An order's fulfillment status */ + fulfillmentStatus?: Maybe<Array<Maybe<OrderFulfillmentStatus>>> + /** An order's payment status */ + paymentStatus?: Maybe<Array<Maybe<OrderPaymentStatus>>> + /** Keywords typed by the user in the search input field */ + searchField?: Maybe<Scalars['String']> + /** The order's status to filter by */ + status?: Maybe<OrderStatus> +} + +/** An order fulfillment group */ +export type OrderFulfillmentGroup = Node & { + __typename?: 'OrderFulfillmentGroup' + /** The order fulfillment group ID */ + _id: Scalars['ID'] + /** Information needed by the selected fulfillment method to properly fulfill the order */ + data?: Maybe<OrderFulfillmentGroupData> + /** The order status for display in UI */ + displayStatus: Scalars['String'] + /** The items that are part of this fulfillment group */ + items?: Maybe<OrderItemConnection> + /** The fulfillment method that was selected, with its price quote */ + selectedFulfillmentOption: FulfillmentOption + /** The shipping label URL */ + shippingLabelUrl?: Maybe<Scalars['String']> + /** The shop responsible for fulfilling this order */ + shop: Shop + /** The machine-readable fulfillment group status. */ + status: Scalars['String'] + /** A summary of the totals for this group */ + summary: OrderSummary + /** Total quantity of all items in the group */ + totalItemQuantity: Scalars['Int'] + /** The order fulfillment group shipment tracking number */ + tracking?: Maybe<Scalars['String']> + /** The order fulfillment group shipment tracking URL */ + trackingUrl?: Maybe<Scalars['String']> + /** The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital` */ + type: FulfillmentType + /** A summary of calculated taxes for this group. */ + taxSummary?: Maybe<TaxSummary> +} + +/** An order fulfillment group */ +export type OrderFulfillmentGroupDisplayStatusArgs = { + language: Scalars['String'] +} + +/** An order fulfillment group */ +export type OrderFulfillmentGroupItemsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<OrderFulfillmentGroupItemsSortByField> +} + +/** Extra data for an order fulfillment group */ +export type OrderFulfillmentGroupData = ShippingOrderFulfillmentGroupData + +/** Information needed by the selected fulfillment method to properly fulfill the order */ +export type OrderFulfillmentGroupDataInput = { + /** The mailing address to which this fulfillment group should be shipped */ + shippingAddress?: Maybe<AddressInput> +} + +/** Similar to `OrderFulfillmentGroupInput` but `items` can be omitted if moving existing items to the new group */ +export type OrderFulfillmentGroupExistingOrderInput = { + /** Information needed by the selected fulfillment method to properly fulfill the order */ + data?: Maybe<OrderFulfillmentGroupDataInput> + /** The list of items to be ordered */ + items?: Maybe<Array<Maybe<OrderFulfillmentGroupItemInput>>> + /** The ID of the fulfillment method to be used for this order group */ + selectedFulfillmentMethodId: Scalars['ID'] + /** The shop that owns these items and needs to fulfill this part of the order */ + shopId: Scalars['ID'] + /** + * The total price of the items, fulfillment, and taxes, for this group, less any discounts, in the + * `order.currencyCode` currency. This value is not trusted; the actual total is calculated by the + * Order service. However, providing this value prevents an order being created for an amount that + * does not match what was shown to the shopper in order preview. + */ + totalPrice?: Maybe<Scalars['Float']> + /** The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital` */ + type: FulfillmentType +} + +/** Input for an `OrderFulfillmentGroup` */ +export type OrderFulfillmentGroupInput = { + /** Information needed by the selected fulfillment method to properly fulfill the order */ + data?: Maybe<OrderFulfillmentGroupDataInput> + /** The list of items to be ordered */ + items: Array<Maybe<OrderFulfillmentGroupItemInput>> + /** The ID of the fulfillment method to be used for this order group */ + selectedFulfillmentMethodId: Scalars['ID'] + /** The shop that owns these items and needs to fulfill this part of the order */ + shopId: Scalars['ID'] + /** + * The total price of the items, fulfillment, and taxes, for this group, less any discounts, in the + * `order.currencyCode` currency. This value is not trusted; the actual total is calculated by the + * Order service. However, providing this value prevents an order being created for an amount that + * does not match what was shown to the shopper in order preview. + */ + totalPrice?: Maybe<Scalars['Float']> + /** The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital` */ + type: FulfillmentType +} + +/** Input for an `OrderFulfillmentGroupItem` */ +export type OrderFulfillmentGroupItemInput = { + /** The date and time at which this item was first added to the source cart, if this is something you want to track */ + addedAt?: Maybe<Scalars['DateTime']> + /** + * The price of the item, in the `order.currencyCode` currency. This value is not trusted; the actual price + * is confirmed by the Order service. However, providing this value prevents an order being created for an + * amount that does not match what was shown to the shopper in order preview. + */ + price: Scalars['Float'] + /** The product and chosen options */ + productConfiguration: ProductConfigurationInput + /** The desired quantity of this item. This must be a positive integer. */ + quantity: Scalars['Int'] +} + +/** Allowed values for the `OrderFulfillmentGroupItems` sortBy parameter */ +export enum OrderFulfillmentGroupItemsSortByField { + /** Sort by the item ID */ + Id = '_id', + /** Sort by the date and time when the item was added to the order */ + AddedAt = 'addedAt', +} + +/** Available order fulfillment statuses */ +export enum OrderFulfillmentStatus { + /** An order that has been completed */ + Completed = 'completed', + /** Newly created order that needs processing */ + New = 'new', + /** An order that is currently being processed */ + Processing = 'processing', +} + +/** Input for placing an order */ +export type OrderInput = { + /** + * The ID of the cart that is becoming an order. This is optional, and you can create an order without ever + * creating a cart. If you do have a cart, there are two good reasons to provide this. First, it serves as a + * reference. Second, it allows the Cart service to automatically delete the related cart after the order is + * created. + */ + cartId?: Maybe<Scalars['String']> + /** The code for the currency in which all values are being provided */ + currencyCode: Scalars['String'] + /** + * An email address to use for order tracking and correspondence. If a logged in user is placing an order, + * we recommend that you use their "orders" email address, if they have one, or their default email address. + * Or you can ask them to provide any email address. + */ + email: Scalars['String'] + /** + * One or more fulfillment groups for the order. These are the actual orders that need to be fulfilled, + * separate by shop, fulfillment type, and shipping origin or destination. + */ + fulfillmentGroups: Array<Maybe<OrderFulfillmentGroupInput>> + /** + * The shop through which the order should be placed. Payment settings from this shop will be used. Note that + * each fulfillment group also has a shop ID, which represents the shop that needs to fulfill that part of the + * order, and those shop IDs may or may not match this one. + */ + shopId: Scalars['String'] +} + +/** A single item in an order. The item contains information about a purchase. */ +export type OrderItem = Node & { + __typename?: 'OrderItem' + /** The order item ID */ + _id: Scalars['ID'] + /** + * " + * The date and time at which this item was first added to the associated cart. + * If an item is added, removed, and then added again, this will reflect the most recent addition. + * However, if an item is added twice, the quantity will increase but this date will remain + * the initial added date. + */ + addedAt?: Maybe<Scalars['DateTime']> + /** + * FUTURE. Additional attributes of the chosen item. For example, if this item is for a product, socks, where `blue` and `small` + * options were chosen for some configurable attributes, then `color:blue` and `size:small` will be indicated here. + */ + attributes?: Maybe<Array<Maybe<OrderItemAttribute>>> + /** If this order item is canceled, the reason for cancelation, if provided */ + cancelReason?: Maybe<Scalars['String']> + /** The date and time at which the order item was created */ + createdAt: Scalars['DateTime'] + /** The URLs for a picture of the item in various sizes */ + imageURLs?: Maybe<ImageSizes> + /** Arbitrary additional metadata about this cart item. */ + metafields?: Maybe<Array<Maybe<Metafield>>> + /** The short title of the associated option, if this is an option item */ + optionTitle?: Maybe<Scalars['String']> + /** Packing information such as item weight, height, length, and depth. Used for calculating shipping rates. */ + parcel?: Maybe<ShippingParcel> + /** The price of the item at the time of purchase */ + price: Money + /** The product and chosen options */ + productConfiguration: ProductConfiguration + /** The product's slug */ + productSlug?: Maybe<Scalars['String']> + /** The list of tags that have been applied to this product */ + productTags?: Maybe<TagConnection> + /** The type of product, used to display cart items differently */ + productType?: Maybe<Scalars['String']> + /** The product vendor */ + productVendor?: Maybe<Scalars['String']> + /** The quantity of this item that has been added to the cart. This must be a positive integer. Remove this `CartItem` from it's associated cart if you want `0` of this item. */ + quantity: Scalars['Int'] + /** The shop associated with this cart item. */ + shop: Shop + /** The machine-readable order item status. */ + status: Scalars['String'] + /** The price of the item multiplied by the quantity of this item ordered */ + subtotal: Money + /** A title for use in orders that conveys the selected product's title + chosen options */ + title: Scalars['String'] + /** The date and time at which this item was last updated */ + updatedAt: Scalars['DateTime'] + /** The selected variant title */ + variantTitle?: Maybe<Scalars['String']> + /** Is this a taxable item? */ + isTaxable: Scalars['Boolean'] + /** Total tax calculated for this item */ + tax: Money + /** The tax code for this item */ + taxCode?: Maybe<Scalars['String']> + /** Amount of subtotal that is taxable */ + taxableAmount: Money + /** List of calculated taxes due for this item */ + taxes: Array<Maybe<CalculatedTax>> +} + +/** A single item in an order. The item contains information about a purchase. */ +export type OrderItemProductTagsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<TagSortByField> +} + +/** One attribute of an order item */ +export type OrderItemAttribute = { + __typename?: 'OrderItemAttribute' + /** The attribute label, e.g., Color */ + label?: Maybe<Scalars['String']> + /** The attribute value, e.g., Blue */ + value?: Maybe<Scalars['String']> +} + +/** + * Wraps a list of `OrderItem`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type OrderItemConnection = { + __typename?: 'OrderItemConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<OrderItemEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<OrderItem>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `OrderItem` object */ +export type OrderItemEdge = NodeEdge & { + __typename?: 'OrderItemEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The order item */ + node?: Maybe<OrderItem> +} + +/** A note about an order */ +export type OrderNote = { + __typename?: 'OrderNote' + /** The account who wrote this note */ + account: Account + /** The content of the note */ + content: Scalars['String'] + /** The date and time at which this note was created */ + createdAt: Scalars['DateTime'] + /** The date and time at which this note was last updated */ + updatedAt: Scalars['DateTime'] +} + +/** Order payment status */ +export enum OrderPaymentStatus { + /** Payments that have been successfully processed */ + Completed = 'completed', + /** A payment intent has been created */ + Created = 'created', +} + +/** Order status */ +export enum OrderStatus { + /** Canceled order */ + Canceled = 'canceled', + /** A completed order */ + Completed = 'completed', + /** A new order that needs processing */ + New = 'new', + /** An order that is being processed */ + Processing = 'processing', +} + +/** A summary of the totals for this order */ +export type OrderSummary = { + __typename?: 'OrderSummary' + /** The total of all discounts applied, as a positive number */ + discountTotal: Money + /** The calculated tax-exclusive tax rate on all items and fulfillment prices (taxTotal / taxableAmount) */ + effectiveTaxRate: Rate + /** The total price of all chosen fulfillment methods */ + fulfillmentTotal: Money + /** The combined prices of all cart items */ + itemTotal: Money + /** The total estimated tax that has not already been included in the item prices */ + taxTotal: Money + /** The total amount that was deemed taxable by the tax service */ + taxableAmount: Money + /** The sum of `itemTotal`, `fulfillmentTotal`, and `taxTotal`, minus `discountTotal` */ + total: Money + /** The total of all suurcharges applied */ + surchargeTotal?: Maybe<Money> +} + +/** + * Wraps a list of `Order`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type OrdersByAccountIdConnection = { + __typename?: 'OrdersByAccountIdConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<OrdersByAccountIdEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Order>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `Order` object */ +export type OrdersByAccountIdEdge = NodeEdge & { + __typename?: 'OrdersByAccountIdEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The order */ + node?: Maybe<Order> +} + +/** The fields by which you are allowed to sort any query that returns a `OrdersByAccountIdConnection` */ +export enum OrdersByAccountIdSortByField { + /** Sort by the order ID */ + Id = '_id', + /** Sort by the date and time when the order was placed */ + CreatedAt = 'createdAt', +} + +/** The fields by which you are allowed to sort any query that returns a `OrderConnection` */ +export enum OrdersSortByField { + /** Sort by the order ID */ + Id = '_id', + /** Sort by the date and time when the order was placed */ + CreatedAt = 'createdAt', +} + +/** + * Pagination information. When requesting pages of results, you can use endCursor or startCursor + * as your before or after parameters for the query you are paging. + */ +export type PageInfo = { + __typename?: 'PageInfo' + /** When paginating forwards, the cursor to continue. */ + endCursor?: Maybe<Scalars['ConnectionCursor']> + /** When paginating forwards, are there more items? */ + hasNextPage: Scalars['Boolean'] + /** When paginating backwards, are there more items? */ + hasPreviousPage: Scalars['Boolean'] + /** When paginating backwards, the cursor to continue. */ + startCursor?: Maybe<Scalars['ConnectionCursor']> +} + +/** Information about a payment made */ +export type Payment = Node & { + __typename?: 'Payment' + /** The Payment ID */ + _id: Scalars['ID'] + /** + * The amount that will be applied to this payment method. If there are multiple payment methods applied to the + * cart, this may be less than the cart total. + */ + amount: Money + /** The billing address for this payment, if one was collected */ + billingAddress?: Maybe<Address> + /** If status is `error` due to a capture error, this code describes the error in a machine-readable way. */ + captureErrorCode?: Maybe<Scalars['String']> + /** If status is `error` due to a capture error, this code describes the error in a human-readable way. */ + captureErrorMessage?: Maybe<Scalars['String']> + /** For card payments, the brand of the card. Useful for showing card icons for common brands. */ + cardBrand?: Maybe<Scalars['String']> + /** The date and time at which this payment was created */ + createdAt: Scalars['DateTime'] + /** + * The shopper-provided data needed to complete the payment using this method. + * For example, a billing address, store credit code, stored credit card ID, etc. + */ + data?: Maybe<PaymentData> + /** Use this identifier when showing this payment in a user interface */ + displayName: Scalars['String'] + /** Has the payment authorization been canceled? */ + isAuthorizationCanceled: Scalars['Boolean'] + /** Has the payment been captured? If false, it is just an authorization. */ + isCaptured: Scalars['Boolean'] + /** The payment method */ + method: PaymentMethod + /** The payment mode */ + mode?: Maybe<Scalars['String']> + /** The payment processor */ + processor?: Maybe<Scalars['String']> + /** Refunds that have been applied to this payment. */ + refunds?: Maybe<Array<Maybe<Refund>>> + /** Risk level of payment */ + riskLevel?: Maybe<RiskLevel> + /** The current status of this payment */ + status: PaymentStatus + /** The payment transaction ID */ + transactionId?: Maybe<Scalars['String']> +} + +/** Data identifying a payment for an order */ +export type PaymentData = + | FakeData + | StripeCardPaymentData + | ExampleIouPaymentData + +/** Input for adding order payments */ +export type PaymentInput = { + /** + * Amount to charge, which must be less than or equal to the order total. This is assumed + * to be in the same currency as the order. Set to `null` to charge the remaining amount + * to this payment method, which might be the full order total if this is the only payment. + */ + amount: Scalars['Float'] + /** + * The billing address entered by the shopper. If omitted, the billing address on the order input + * will be used. Some payment methods may not require a billing address but others will fail + * authorization without one, so be sure that client UI code is aware of which payment methods + * require collecting one. + */ + billingAddress?: Maybe<AddressInput> + /** Any additional user-provided input necessary to authorize and capture the payment */ + data?: Maybe<Scalars['JSONObject']> + /** The name of the payment method to use for this payment */ + method: PaymentMethodName +} + +/** Describes a payment method */ +export type PaymentMethod = { + __typename?: 'PaymentMethod' + /** If this is `false`, the payment method does not support refunding. Use this to hide refund UI. */ + canRefund: Scalars['Boolean'] + /** Data for this method. The data format differs for each method */ + data?: Maybe<PaymentMethodData> + /** Human-readable display name */ + displayName: Scalars['String'] + /** Whether the payment method is enabled on a given shop */ + isEnabled: Scalars['Boolean'] + /** The payment method name. Any valid name that has been registered by a payment plugin. e.g., saved_card */ + name: Scalars['String'] + /** Name of the plugin that added the payment method */ + pluginName: Scalars['String'] +} + +/** Any extra data needed by the payment method */ +export type PaymentMethodData = FakeData | ExampleIouPaymentMethodData + +/** The name of a payment method, which is how payment methods are keyed */ +export enum PaymentMethodName { + /** No payment method */ + None = 'none', + /** Stripe Card payment method */ + StripeCard = 'stripe_card', + /** IOU Example payment method */ + IouExample = 'iou_example', +} + +/** Valid payment statuses */ +export enum PaymentStatus { + /** A shop operator adjusted the payment amount after the order was placed */ + Adjustments = 'adjustments', + /** A shop operator has approved this payment */ + Approved = 'approved', + /** A shop operator has canceled this payment before it was captured */ + Canceled = 'canceled', + /** A shop operator has captured this payment */ + Completed = 'completed', + /** Upon placing an order, the status of all payments for that order begins at 'created' */ + Created = 'created', + /** There was an error capturing the payment */ + Error = 'error', + /** A shop operator has refunded some but not all of this payment */ + PartialRefund = 'partialRefund', + /** A shop operator has refunded all of this payment */ + Refunded = 'refunded', +} + +/** Input for the placeOrder mutation */ +export type PlaceOrderInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The order to be placed, if payment is accepted */ + order: OrderInput + /** + * The information necessary to pay. Collect this information from the shopper during a checkout flow. + * You need not provide any payment input if the total is zero. + * The total of all payment input `amount` fields must add up to the order total. The first payment + * method where the `amount` field is `null` will be charged the remainder due. + */ + payments?: Maybe<Array<Maybe<PaymentInput>>> +} + +/** Response payload for the placeOrder mutation */ +export type PlaceOrderPayload = { + __typename?: 'PlaceOrderPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Orders that were created */ + orders: Array<Maybe<Order>> + /** If you are not logged in, this will be a token that can be used for future requests */ + token?: Maybe<Scalars['String']> +} + +/** Represents Reaction Plugin */ +export type Plugin = { + __typename?: 'Plugin' + /** Name of plugin */ + name: Scalars['String'] + /** Version of plugin */ + version?: Maybe<Scalars['String']> +} + +/** A Reaction product */ +export type Product = { + __typename?: 'Product' + /** Product ID */ + _id: Scalars['ID'] + /** The date and time at which this product was created */ + createdAt: Scalars['DateTime'] + /** Hash to compare with publishedProductHash, to see if this product has changed since it was last published */ + currentProductHash?: Maybe<Scalars['String']> + /** The full product description, which may have newline characters in it */ + description?: Maybe<Scalars['String']> + /** True if this product has been deleted. Typically, deleted products are not returned in queries. */ + isDeleted: Scalars['Boolean'] + /** True if this product should be shown to shoppers. Typically, non-visible products are not returned in queries. */ + isVisible: Scalars['Boolean'] + /** All media for a product */ + media?: Maybe<Array<Maybe<ImageInfo>>> + /** The product description to use for page `description` meta element in HTML */ + metaDescription?: Maybe<Scalars['String']> + /** Arbitrary additional metadata about this product */ + metafields: Array<Maybe<Metafield>> + /** The country of origin */ + originCountry?: Maybe<Scalars['String']> + /** Subtitle */ + pageTitle?: Maybe<Scalars['String']> + /** An arbitrary product type value, such as from an external system */ + productType?: Maybe<Scalars['String']> + /** The date and time at which this product was last published. If `null`, it has never been published. */ + publishedAt?: Maybe<Scalars['DateTime']> + /** Hash to compare with currentProductHash, to see if this product has changed since it was last published */ + publishedProductHash?: Maybe<Scalars['String']> + /** The shop to which this product belongs */ + shop: Shop + /** Whether this product will be shown in the generated sitemap */ + shouldAppearInSitemap?: Maybe<Scalars['Boolean']> + /** A URL-safe and human-readable string that uniquely identifies this product */ + slug?: Maybe<Scalars['String']> + /** Holds metadata specific to a specific social network service */ + socialMetadata?: Maybe<Array<Maybe<SocialMetadata>>> + /** When a shopper purchases this product, what types of fulfillment can they choose from? */ + supportedFulfillmentTypes: Array<Maybe<FulfillmentType>> + /** The list of tag IDs that have been applied to this product */ + tagIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** The list of tags that have been applied to this product */ + tags?: Maybe<TagConnection> + /** Product title */ + title?: Maybe<Scalars['String']> + /** The date and time at which this product was last updated */ + updatedAt?: Maybe<Scalars['DateTime']> + /** A list of all variants for this product */ + variants: Array<Maybe<ProductVariant>> + /** The product vendor or manufacturer, for display */ + vendor?: Maybe<Scalars['String']> + /** + * Price range + * @deprecated Use `pricing` + */ + price?: Maybe<ProductPriceRange> + /** Pricing information */ + pricing: ProductPricingInfo +} + +/** A Reaction product */ +export type ProductMediaArgs = { + shouldIncludeVariantMedia?: Maybe<Scalars['Boolean']> +} + +/** A Reaction product */ +export type ProductTagsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<TagSortByField> +} + +/** A Reaction product */ +export type ProductVariantsArgs = { + shouldIncludeHidden?: Maybe<Scalars['Boolean']> + shouldIncludeArchived?: Maybe<Scalars['Boolean']> +} + +/** Product configuration data */ +export type ProductConfiguration = { + __typename?: 'ProductConfiguration' + /** The Product ID */ + productId: Scalars['ID'] + /** The ProductVariant ID */ + productVariantId: Scalars['ID'] +} + +/** Input that defines a single configuration of a product */ +export type ProductConfigurationInput = { + /** The Product ID */ + productId: Scalars['ID'] + /** The ProductVariant ID */ + productVariantId: Scalars['ID'] +} + +/** + * Wraps a list of Products`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type ProductConnection = { + __typename?: 'ProductConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<ProductEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Product>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `Product` object */ +export type ProductEdge = { + __typename?: 'ProductEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The product */ + node?: Maybe<Product> +} + +/** Mutation input for a product */ +export type ProductInput = { + /** + * Any string to use as the internal ID for a new product. Do not prefix or base64 encode this ID. + * This field is allowed only when creating a product. If you include an ID for an update, you + * will get an error. The string must also be different from any existing product, variant, or + * option internal ID or you will get a duplicate ID error. If you do not include this when creating + * a product, a random unique string is generated for you. + */ + _id?: Maybe<Scalars['String']> + /** The full product description, which may have newline characters in it */ + description?: Maybe<Scalars['String']> + /** Facebook message */ + facebookMsg?: Maybe<Scalars['String']> + /** Google message */ + googleplusMsg?: Maybe<Scalars['String']> + /** True if this product has been deleted. Typically, deleted products are not returned in queries. */ + isDeleted?: Maybe<Scalars['Boolean']> + /** True if this product should be shown to shoppers. Typically, non-visible products are not returned in queries. */ + isVisible?: Maybe<Scalars['Boolean']> + /** The product description to use for page `description` meta element in HTML */ + metaDescription?: Maybe<Scalars['String']> + /** Arbitrary additional metadata about this product */ + metafields?: Maybe<Array<Maybe<MetafieldInput>>> + /** The country of origin */ + originCountry?: Maybe<Scalars['String']> + /** Subtitle */ + pageTitle?: Maybe<Scalars['String']> + /** Pinterest message */ + pinterestMsg?: Maybe<Scalars['String']> + /** An arbitrary product type value, such as from an external system */ + productType?: Maybe<Scalars['String']> + /** Whether this product will be shown in the generated sitemap */ + shouldAppearInSitemap?: Maybe<Scalars['Boolean']> + /** A URL-safe and human-readable string that uniquely identifies this product */ + slug?: Maybe<Scalars['String']> + /** When a shopper purchases this product, what types of fulfillment can they choose from? */ + supportedFulfillmentTypes?: Maybe<Array<Maybe<FulfillmentType>>> + /** The list of tag IDs that have been applied to this product */ + tagIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** Product title */ + title?: Maybe<Scalars['String']> + /** Twitter message */ + twitterMsg?: Maybe<Scalars['String']> + /** The product vendor or manufacturer, for display */ + vendor?: Maybe<Scalars['String']> +} + +/** Product price range */ +export type ProductPriceRange = { + __typename?: 'ProductPriceRange' + /** Maximum price in range */ + max?: Maybe<Scalars['Float']> + /** Minimum price in range */ + min?: Maybe<Scalars['Float']> + /** Price range display */ + range?: Maybe<Scalars['String']> +} + +/** The product price or price range for a specific currency */ +export type ProductPricingInfo = { + __typename?: 'ProductPricingInfo' + /** + * A comparison price value, usually MSRP. If `price` is null, this will also be null. That is, + * only purchasable variants will have a `compareAtPrice`. + */ + compareAtPrice?: Maybe<Money> + /** The code for the currency these pricing details applies to */ + currency: Currency + /** Pricing converted to specified currency */ + currencyExchangePricing?: Maybe<CurrencyExchangeProductPricingInfo> + /** + * UI should display this price. If a product has multiple potential prices depending on selected + * variants and options, then this is a price range string such as "$3.95 - $6.99". It includes the currency + * symbols. + */ + displayPrice: Scalars['String'] + /** The price of the most expensive possible variant+option combination */ + maxPrice: Scalars['Float'] + /** The price of the least expensive possible variant+option combination */ + minPrice: Scalars['Float'] + /** + * For variants with no options and for options, this will always be set to a price. For variants + * with options and products, this will be `null`. There must be a price for a variant to be + * added to a cart or purchased. Otherwise you would instead add one of its child options to a cart. + */ + price?: Maybe<Scalars['Float']> +} + +/** The product price or price range for a specific currency */ +export type ProductPricingInfoCurrencyExchangePricingArgs = { + currencyCode: Scalars['String'] +} + +/** The fields by which you are allowed to sort any query that returns a `ProductConnection` */ +export enum ProductSortByField { + /** Product ID */ + Id = '_id', + /** Date and time the product was created */ + CreatedAt = 'createdAt', + /** Product title */ + Title = 'title', + /** Date and time the product was last updated */ + UpdatedAt = 'updatedAt', +} + +/** Input for adding tags to products in bulk */ +export type ProductTagsOperationInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** An array of product productIds to which an array of tags will be added */ + productIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** The shop id */ + shopId: Scalars['ID'] + /** An array of tag ids to add to an array of products */ + tagIds?: Maybe<Array<Maybe<Scalars['ID']>>> +} + +/** Response payload managing tags on products */ +export type ProductTagsOperationPayload = { + __typename?: 'ProductTagsOperationPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The number of products found */ + foundCount?: Maybe<Scalars['Int']> + /** The number of products for which a match was not found */ + notFoundCount?: Maybe<Scalars['Int']> + /** The number of products successfully updated */ + updatedCount?: Maybe<Scalars['Int']> + /** An array of write errors if any were generated */ + writeErrors?: Maybe<Array<Maybe<WriteError>>> +} + +/** A Reaction product variant or option */ +export type ProductVariant = { + __typename?: 'ProductVariant' + /** Variant ID */ + _id: Scalars['ID'] + /** + * The attribute label describes the category of variant, for example, `Color` or `Size`. + * In most cases this will be the same for all variants at the same level. + */ + attributeLabel?: Maybe<Scalars['String']> + /** The product variant barcode value, if it has one */ + barcode?: Maybe<Scalars['String']> + /** The date and time at which this variant was created */ + createdAt?: Maybe<Scalars['DateTime']> + /** The height of the product variant, if it has physical dimensions */ + height?: Maybe<Scalars['Float']> + /** The position of this variant among other variants at the same level of the product-variant-option hierarchy */ + index?: Maybe<Scalars['Int']> + /** True if this variant was deleted. Deleted variants are not published to the catalog. */ + isDeleted: Scalars['Boolean'] + /** True if this variant is visible. Hidden variants are not published to the catalog. */ + isVisible: Scalars['Boolean'] + /** The length of the product, if it has physical dimensions */ + length?: Maybe<Scalars['Float']> + /** All media for a variant */ + media?: Maybe<Array<Maybe<ImageInfo>>> + /** Arbitrary additional metadata about this product */ + metafields: Array<Maybe<Metafield>> + /** The minimum quantity that must be added to a cart */ + minOrderQuantity?: Maybe<Scalars['Int']> + /** A short title to use for product detail select lists */ + optionTitle?: Maybe<Scalars['String']> + /** Child variants, if any */ + options: Array<Maybe<ProductVariant>> + /** The country of origin */ + originCountry?: Maybe<Scalars['String']> + /** The shop to which this product variant belongs */ + shop: Shop + /** SKU of variant */ + sku?: Maybe<Scalars['String']> + /** + * The full variant title for use on cart, checkout, and order summaries and on invoices. + * This fully describes the configured variant. For example, if this is an option with + * `optionTitle` "Large", its parent variant has `optionTitle` `Red`, and the product + * `title` is "Fancy T-Shirt", then this `title` will be something like `Fancy T-Shirt - Red - Large`. + */ + title?: Maybe<Scalars['String']> + /** The date and time at which this product was last updated */ + updatedAt?: Maybe<Scalars['DateTime']> + /** The weight of the product on Earth, if it has physical dimensions */ + weight?: Maybe<Scalars['Float']> + /** The width of the product, if it has physical dimensions */ + width?: Maybe<Scalars['Float']> + /** + * Compare at price of the variant + * @deprecated Use `pricing` + */ + compareAtPrice?: Maybe<Scalars['Float']> + /** + * Price of the variant + * @deprecated Use `pricing` + */ + price?: Maybe<Scalars['Float']> + /** Pricing information */ + pricing: ProductPricingInfo + /** Whether this variant is taxable */ + isTaxable?: Maybe<Scalars['Boolean']> + /** Tax code */ + taxCode?: Maybe<Scalars['String']> + /** Tax description */ + taxDescription?: Maybe<Scalars['String']> +} + +/** A Reaction product variant or option */ +export type ProductVariantOptionsArgs = { + shouldIncludeHidden?: Maybe<Scalars['Boolean']> + shouldIncludeArchived?: Maybe<Scalars['Boolean']> +} + +/** Mutation input for a product variant or option */ +export type ProductVariantInput = { + /** + * Any string to use as the internal ID for a new variant. Do not prefix or base64 encode this ID. + * This field is allowed only when creating a variant. If you include an ID for an update, you + * will get an error. The string must also be different from any existing product, variant, or + * option internal ID or you will get a duplicate ID error. If you do not include this when creating + * a variant, a random unique string is generated for you. + */ + _id?: Maybe<Scalars['String']> + /** + * The attribute label describes the category of variant, for example, `Color` or `Size`. + * In most cases this will be the same for all variants at the same level. + */ + attributeLabel?: Maybe<Scalars['String']> + /** The product variant barcode value, if it has one */ + barcode?: Maybe<Scalars['String']> + /** The height of the product variant, if it has physical dimensions */ + height?: Maybe<Scalars['Float']> + /** The position of this variant among other variants at the same level of the product-variant-option hierarchy */ + index?: Maybe<Scalars['Int']> + /** True if this variant was deleted. Deleted variants are not published to the catalog. */ + isDeleted?: Maybe<Scalars['Boolean']> + /** True if this variant is visible. Hidden variants are not published to the catalog. */ + isVisible?: Maybe<Scalars['Boolean']> + /** The length of the product, if it has physical dimensions */ + length?: Maybe<Scalars['Float']> + /** Arbitrary additional metadata about this product */ + metafields?: Maybe<Array<Maybe<MetafieldInput>>> + /** The minimum quantity that must be added to a cart */ + minOrderQuantity?: Maybe<Scalars['Int']> + /** A short title to use for product detail select lists */ + optionTitle?: Maybe<Scalars['String']> + /** The country of origin */ + originCountry?: Maybe<Scalars['String']> + /** SKU of variant */ + sku?: Maybe<Scalars['String']> + /** + * The full variant title for use on cart, checkout, and order summaries and on invoices. + * This fully describes the configured variant. For example, if this is an option with + * `optionTitle` `Large`, its parent variant has `optionTitle` `Red`, and the product + * `title` is `Fancy T-Shirt`, then this `title` will be something like `Fancy T-Shirt - Red - Large`. + */ + title?: Maybe<Scalars['String']> + /** The weight of the product on Earth, if it has physical dimensions */ + weight?: Maybe<Scalars['Float']> + /** The width of the product, if it has physical dimensions */ + width?: Maybe<Scalars['Float']> + /** Variant compareAtPrice. DEPRECATED. Use the `updateProductVariantPrices` mutation to set product variant prices. */ + compareAtPrice?: Maybe<Scalars['Float']> + /** Variant price. DEPRECATED. Use the `updateProductVariantPrices` mutation to set product variant prices. */ + price?: Maybe<Scalars['Float']> + /** Whether this variant is taxable */ + isTaxable?: Maybe<Scalars['Boolean']> + /** Tax code */ + taxCode?: Maybe<Scalars['String']> + /** Tax description */ + taxDescription?: Maybe<Scalars['String']> +} + +/** Mutation input for a product variant or option */ +export type ProductVariantPricesInput = { + /** Variant compareAtPrice */ + compareAtPrice?: Maybe<Scalars['Float']> + /** Variant price */ + price?: Maybe<Scalars['Float']> +} + +/** Input for the `publishNavigationChanges` mutation */ +export type PublishNavigationChangesInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the navigation tree */ + id: Scalars['ID'] + /** Shop ID of the navigation tree */ + shopId: Scalars['ID'] +} + +/** Response payload for the `publishNavigationChanges` mutation */ +export type PublishNavigationChangesPayload = { + __typename?: 'PublishNavigationChangesPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The navigation tree with updated items */ + navigationTree?: Maybe<NavigationTree> +} + +export type Query = { + __typename?: 'Query' + /** A test query */ + ping: Scalars['String'] + /** Returns the primary shop for the domain */ + primaryShop?: Maybe<Shop> + /** Returns the ID of the primary shop for the domain */ + primaryShopId?: Maybe<Scalars['ID']> + /** Returns a shop by ID */ + shop?: Maybe<Shop> + /** Returns a shop by slug */ + shopBySlug?: Maybe<Shop> + shops?: Maybe<ShopConnection> + /** + * Returns app settings that are not shop specific. Plugins extend the GlobalSettings type to support + * whatever settings they need. + */ + globalSettings: GlobalSettings + /** + * Returns app settings for a specific shop. Plugins extend the ShopSettings type to support + * whatever settings they need. + */ + shopSettings: ShopSettings + /** + * Get a list of errors and suggested properly formatted addresses for an address. If no address + * validation service is active for the shop, this will return as if the address is valid even + * though no check actually occurred. + */ + addressValidation: AddressValidationResults + /** Get a full list of all registered address validation services */ + addressValidationServices: Array<Maybe<AddressValidationService>> + /** Returns a list of defined address validation rules for a shop */ + addressValidationRules: AddressValidationRuleConnection + /** SystemInformation object */ + systemInformation: SystemInformation + /** Retrieves a list of email templates */ + emailTemplates?: Maybe<TemplateConnection> + /** Returns the account with the provided ID */ + account?: Maybe<Account> + /** Returns accounts optionally filtered by account groups */ + accounts: AccountConnection + /** Returns customer accounts */ + customers: AccountConnection + /** Returns the account for the authenticated user */ + viewer?: Maybe<Account> + /** Returns a single group by ID. */ + group?: Maybe<Group> + /** Returns a list of groups for the shop with ID `shopId`, as a Relay-compatible connection. */ + groups?: Maybe<GroupConnection> + /** Returns all pending staff member invitations */ + invitations: InvitationConnection + /** Returns a paged list of all roles associated with a shop */ + roles?: Maybe<RoleConnection> + /** Query for a single Product */ + product?: Maybe<Product> + /** Query for a list of Products */ + products?: Maybe<ProductConnection> + /** Gets items from a shop catalog */ + catalogItems?: Maybe<CatalogItemConnection> + /** Gets product from catalog */ + catalogItemProduct?: Maybe<CatalogItemProduct> + /** Gets an array of all vendors */ + vendors?: Maybe<VendorConnection> + /** Returns a list of product in a tag */ + productsByTagId: TagProductConnection + /** Returns a tag from a provided tag ID or slug. Tags with isVisible set to false are excluded by default. */ + tag?: Maybe<Tag> + /** Returns a paged list of tags for a shop. You must include a shopId when querying. */ + tags?: Maybe<TagConnection> + /** + * Get the SimpleInventory info for a product configuration. Returns `null` if `updateSimpleInventory` + * has never been called for this product configuration. + */ + simpleInventory?: Maybe<SimpleInventoryInfo> + /** Finds a cart by the cart ID and anonymous cart token. */ + anonymousCartByCartId?: Maybe<Cart> + /** Find a cart for a given account ID. */ + accountCartByAccountId?: Maybe<Cart> + /** Get an order by its ID */ + orderById?: Maybe<Order> + /** Get all orders for a single account, optionally limited to certain shop IDs and certain orderStatus */ + orders: OrderConnection + /** Get all orders for a single account, optionally limited to certain shop IDs and certain orderStatus */ + ordersByAccountId: OrdersByAccountIdConnection + /** Get an order by its reference ID (the ID shown to customers) */ + orderByReferenceId?: Maybe<Order> + /** Get refunds applied to an order by order ID */ + refunds?: Maybe<Array<Maybe<Refund>>> + /** Get refunds applied to a specific payment by payment ID */ + refundsByPaymentId?: Maybe<Array<Maybe<Refund>>> + /** + * Get a list of all payment methods available during a checkout. This may filter by auth, + * active/inactive, IP/region, shop, etc. To get the full list, use the `paymentMethods` + * query with proper authorization. + */ + availablePaymentMethods: Array<Maybe<PaymentMethod>> + /** Get a full list of all payment methods */ + paymentMethods: Array<Maybe<PaymentMethod>> + /** Gets discount codes */ + discountCodes?: Maybe<DiscountCodeConnection> + /** Get the full list of surcharges. */ + surcharges: SurchargeConnection + /** Get a single surcharge definition by its ID */ + surchargeById?: Maybe<Surcharge> + /** Get a flat rate fulfillment method */ + flatRateFulfillmentMethod: FlatRateFulfillmentMethod + /** Get a flat rate fulfillment methods */ + flatRateFulfillmentMethods: FlatRateFulfillmentMethodConnection + /** Get the full list of flat rate fulfillment method restrictions. */ + getFlatRateFulfillmentRestrictions: FlatRateFulfillmentRestrictionConnection + /** Get a single flat rate fulfillment method restriction. */ + getFlatRateFulfillmentRestriction?: Maybe<FlatRateFulfillmentRestriction> + /** List all tax codes supported by the current active tax service for the shop */ + taxCodes: Array<Maybe<TaxCode>> + /** Get a full list of all tax services for the shop */ + taxServices: Array<Maybe<TaxService>> + /** Gets tax rates */ + taxRates?: Maybe<TaxRateConnection> + /** Returns a navigation tree by its ID in the specified language */ + navigationTreeById?: Maybe<NavigationTree> + /** Returns the navigation items for a shop */ + navigationItemsByShopId?: Maybe<NavigationItemConnection> + /** Returns Sitemap object for a shop based on the handle param */ + sitemap?: Maybe<Sitemap> + twoFactorSecret?: Maybe<TwoFactorSecretKey> + getUser?: Maybe<User> +} + +export type QueryShopArgs = { + id: Scalars['ID'] +} + +export type QueryShopBySlugArgs = { + slug: Scalars['String'] +} + +export type QueryShopsArgs = { + shopIds?: Maybe<Array<Maybe<Scalars['ID']>>> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<GroupSortByField> +} + +export type QueryShopSettingsArgs = { + shopId: Scalars['ID'] +} + +export type QueryAddressValidationArgs = { + address: AddressInput + shopId: Scalars['ID'] +} + +export type QueryAddressValidationRulesArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + serviceNames?: Maybe<Array<Maybe<Scalars['String']>>> + shopId: Scalars['ID'] + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<AddressValidationRuleSortByField> +} + +export type QuerySystemInformationArgs = { + shopId: Scalars['ID'] +} + +export type QueryEmailTemplatesArgs = { + shopId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> +} + +export type QueryAccountArgs = { + id: Scalars['ID'] +} + +export type QueryAccountsArgs = { + groupIds?: Maybe<Array<Maybe<Scalars['ID']>>> + notInAnyGroups?: Maybe<Scalars['Boolean']> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<AccountSortByField> +} + +export type QueryCustomersArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<AccountSortByField> +} + +export type QueryGroupArgs = { + id: Scalars['ID'] +} + +export type QueryGroupsArgs = { + shopId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<GroupSortByField> +} + +export type QueryInvitationsArgs = { + shopIds?: Maybe<Array<Maybe<Scalars['ID']>>> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<AccountSortByField> +} + +export type QueryRolesArgs = { + shopId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<RoleSortByField> +} + +export type QueryProductArgs = { + productId: Scalars['ID'] + shopId: Scalars['ID'] +} + +export type QueryProductsArgs = { + isArchived?: Maybe<Scalars['Boolean']> + isVisible?: Maybe<Scalars['Boolean']> + metafieldKey?: Maybe<Scalars['String']> + metafieldValue?: Maybe<Scalars['String']> + priceMax?: Maybe<Scalars['Float']> + priceMin?: Maybe<Scalars['Float']> + productIds?: Maybe<Array<Maybe<Scalars['ID']>>> + query?: Maybe<Scalars['String']> + shopIds: Array<Maybe<Scalars['ID']>> + tagIds?: Maybe<Array<Maybe<Scalars['ID']>>> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<ProductSortByField> +} + +export type QueryCatalogItemsArgs = { + shopIds: Array<Maybe<Scalars['ID']>> + tagIds?: Maybe<Array<Maybe<Scalars['ID']>>> + booleanFilters?: Maybe<Array<Maybe<CatalogBooleanFilter>>> + searchQuery?: Maybe<Scalars['String']> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortByPriceCurrencyCode?: Maybe<Scalars['String']> + sortBy?: Maybe<CatalogItemSortByField> +} + +export type QueryCatalogItemProductArgs = { + shopId?: Maybe<Scalars['ID']> + slugOrId?: Maybe<Scalars['String']> +} + +export type QueryVendorsArgs = { + shopIds: Array<Maybe<Scalars['ID']>> + tagIds?: Maybe<Array<Maybe<Scalars['ID']>>> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> +} + +export type QueryProductsByTagIdArgs = { + shopId: Scalars['ID'] + tagId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> +} + +export type QueryTagArgs = { + slugOrId: Scalars['String'] + shopId: Scalars['ID'] + shouldIncludeInvisible?: Maybe<Scalars['Boolean']> +} + +export type QueryTagsArgs = { + shopId: Scalars['ID'] + filter?: Maybe<Scalars['String']> + excludedTagIds?: Maybe<Array<Maybe<Scalars['ID']>>> + isTopLevel?: Maybe<Scalars['Boolean']> + shouldIncludeDeleted?: Maybe<Scalars['Boolean']> + shouldIncludeInvisible?: Maybe<Scalars['Boolean']> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<TagSortByField> +} + +export type QuerySimpleInventoryArgs = { + shopId: Scalars['ID'] + productConfiguration: ProductConfigurationInput +} + +export type QueryAnonymousCartByCartIdArgs = { + cartId: Scalars['ID'] + cartToken: Scalars['String'] +} + +export type QueryAccountCartByAccountIdArgs = { + accountId: Scalars['ID'] + shopId: Scalars['ID'] +} + +export type QueryOrderByIdArgs = { + id: Scalars['ID'] + shopId: Scalars['ID'] + token?: Maybe<Scalars['String']> +} + +export type QueryOrdersArgs = { + filters?: Maybe<OrderFilterInput> + shopIds?: Maybe<Array<Maybe<Scalars['ID']>>> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<OrdersSortByField> +} + +export type QueryOrdersByAccountIdArgs = { + accountId: Scalars['ID'] + orderStatus?: Maybe<Array<Maybe<Scalars['String']>>> + shopIds: Array<Maybe<Scalars['ID']>> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<OrdersByAccountIdSortByField> +} + +export type QueryOrderByReferenceIdArgs = { + id: Scalars['ID'] + shopId: Scalars['ID'] + token?: Maybe<Scalars['String']> +} + +export type QueryRefundsArgs = { + orderId: Scalars['ID'] + shopId: Scalars['ID'] + token?: Maybe<Scalars['String']> +} + +export type QueryRefundsByPaymentIdArgs = { + orderId: Scalars['ID'] + paymentId: Scalars['ID'] + shopId: Scalars['ID'] + token?: Maybe<Scalars['String']> +} + +export type QueryAvailablePaymentMethodsArgs = { + shopId: Scalars['ID'] +} + +export type QueryPaymentMethodsArgs = { + shopId: Scalars['ID'] +} + +export type QueryDiscountCodesArgs = { + shopId: Scalars['ID'] + filters?: Maybe<DiscountCodeFilterInput> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> +} + +export type QuerySurchargesArgs = { + shopId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<SurchargeSortByField> +} + +export type QuerySurchargeByIdArgs = { + shopId: Scalars['ID'] + surchargeId: Scalars['ID'] +} + +export type QueryFlatRateFulfillmentMethodArgs = { + methodId: Scalars['ID'] + shopId: Scalars['ID'] +} + +export type QueryFlatRateFulfillmentMethodsArgs = { + shopId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> +} + +export type QueryGetFlatRateFulfillmentRestrictionsArgs = { + shopId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<FlatRateFulfillmentRestrictionSortByField> +} + +export type QueryGetFlatRateFulfillmentRestrictionArgs = { + restrictionId: Scalars['ID'] + shopId: Scalars['ID'] +} + +export type QueryTaxCodesArgs = { + shopId: Scalars['ID'] +} + +export type QueryTaxServicesArgs = { + shopId: Scalars['ID'] +} + +export type QueryTaxRatesArgs = { + shopId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> +} + +export type QueryNavigationTreeByIdArgs = { + id: Scalars['ID'] + language: Scalars['String'] + shopId: Scalars['ID'] + shouldIncludeSecondary?: Maybe<Scalars['Boolean']> +} + +export type QueryNavigationItemsByShopIdArgs = { + shopId: Scalars['ID'] + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<NavigationItemSortByField> +} + +export type QuerySitemapArgs = { + handle: Scalars['String'] + shopUrl: Scalars['String'] +} + +/** A numeric rate, with its corresponding percent values */ +export type Rate = { + __typename?: 'Rate' + /** The rate */ + amount: Scalars['Float'] + /** The percent as a preformatted string with percent symbol included */ + displayPercent: Scalars['String'] + /** The percent (rate x 100) */ + percent: Scalars['Float'] +} + +/** Input for the `recalculateReservedSimpleInventory` mutation */ +export type RecalculateReservedSimpleInventoryInput = { + /** The product and chosen options this info applies to */ + productConfiguration: ProductConfigurationInput + /** Shop that owns the product */ + shopId: Scalars['ID'] +} + +/** Response payload for the `updateSimpleInventory` mutation */ +export type RecalculateReservedSimpleInventoryPayload = { + __typename?: 'RecalculateReservedSimpleInventoryPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated inventory info */ + inventoryInfo: SimpleInventoryInfo +} + +/** Input for the `reconcileCarts` mutation call */ +export type ReconcileCartsInput = { + /** An anonymous cart ID */ + anonymousCartId: Scalars['ID'] + /** An anonymous cart token */ + cartToken: Scalars['String'] + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** + * If both an anonymous cart and a cart for the authenticated account are found, how do we combine them? + * Default mode is `merge`, where all anonymous items are moved into the account cart along with existing + * account cart items, and quantities are combined. + */ + mode?: Maybe<CartReconciliationMode> + /** The ID of the shop that owns both carts */ + shopId: Scalars['ID'] +} + +/** The payload returned from the `reconcileCarts` mutation call */ +export type ReconcileCartsPayload = { + __typename?: 'ReconcileCartsPayload' + /** The account cart, potentially modified */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** A refund of a payment on an order */ +export type Refund = Node & { + __typename?: 'Refund' + /** The refund ID */ + _id: Scalars['ID'] + /** The amount of the refund */ + amount: Money + /** The date and time at which the refund was created */ + createdAt: Scalars['DateTime'] + /** The display name of the payment refunded to */ + paymentDisplayName: Scalars['String'] + /** The ID of the payment this refund is applied to */ + paymentId: Scalars['ID'] + /** The reason for the refund */ + reason?: Maybe<Scalars['String']> +} + +/** Describes which address should be removed from which account */ +export type RemoveAccountAddressBookEntryInput = { + /** The account ID */ + accountId: Scalars['ID'] + /** The address ID */ + addressId: Scalars['ID'] + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** The response from the `removeAccountAddressBookEntry` mutation */ +export type RemoveAccountAddressBookEntryPayload = { + __typename?: 'RemoveAccountAddressBookEntryPayload' + /** The removed address */ + address?: Maybe<Address> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Defines which email address should be removed from which account */ +export type RemoveAccountEmailRecordInput = { + /** The account ID, which defaults to the viewer account */ + accountId?: Maybe<Scalars['ID']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The email address to remove */ + email: Scalars['Email'] +} + +/** The response from the `removeAccountEmailRecord` mutation */ +export type RemoveAccountEmailRecordPayload = { + __typename?: 'RemoveAccountEmailRecordPayload' + /** The account, with updated `emailRecords` */ + account?: Maybe<Account> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Defines a group and account that should be unlinked */ +export type RemoveAccountFromGroupInput = { + /** The account ID */ + accountId: Scalars['ID'] + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The group ID */ + groupId: Scalars['ID'] +} + +/** The response from the `removeAccountFromGroup` mutation */ +export type RemoveAccountFromGroupPayload = { + __typename?: 'RemoveAccountFromGroupPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The removed group */ + group: Group +} + +/** The details for removing a group */ +export type RemoveAccountGroupInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The group ID */ + groupId: Scalars['ID'] + /** The ID of the shop this group belongs to */ + shopId?: Maybe<Scalars['ID']> +} + +/** The response from the `removeGroup` mutation */ +export type RemoveAccountGroupPayload = { + __typename?: 'RemoveAccountGroupPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The removed group */ + group?: Maybe<Group> +} + +/** Input for the `removeCartItems` mutation */ +export type RemoveCartItemsInput = { + /** The cart ID */ + cartId: Scalars['ID'] + /** Array of items to remove from the cart. */ + cartItemIds: Array<Maybe<Scalars['ID']>> + /** If this cart is anonymous, provide the `cartToken` that was returned in the `CreateCartPayload` */ + cartToken?: Maybe<Scalars['String']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** The payload returned from the `removeCartItems` mutation call */ +export type RemoveCartItemsPayload = { + __typename?: 'RemoveCartItemsPayload' + /** The modified cart */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input for an `RemoveDiscountCodeFromCartInput` */ +export type RemoveDiscountCodeFromCartInput = { + /** Cart to add discount to */ + cartId: Scalars['ID'] + /** ID of the discount you want to remove from the cart */ + discountId: Scalars['ID'] + /** Shop cart belongs to */ + shopId: Scalars['ID'] + /** Cart token, if anonymous */ + token?: Maybe<Scalars['String']> +} + +/** Response from the `removeDiscountCodeFromCart` mutation */ +export type RemoveDiscountCodeFromCartPayload = { + __typename?: 'RemoveDiscountCodeFromCartPayload' + /** The updated cart with discount code removed */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input for `removeTag` mutation */ +export type RemoveTagInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of tag to delete */ + id: Scalars['ID'] + /** The shop that owns the tag */ + shopId: Scalars['ID'] +} + +/** Response payload for `removeTag` mutation */ +export type RemoveTagPayload = { + __typename?: 'RemoveTagPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The deleted tag */ + tag: Tag +} + +/** Restriction type */ +export enum RestrictionTypeEnum { + /** Allow */ + Allow = 'allow', + /** Deny */ + Deny = 'deny', +} + +/** Input for `retryFailedEmail` mutation */ +export type RetryFailedEmailInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of Email Job to retry */ + jobId: Scalars['ID'] + /** Shop ID of Email Job */ + shopId: Scalars['ID'] +} + +/** Response payload for `retryFailedEmail` mutation */ +export type RetryFailedEmailPayload = { + __typename?: 'RetryFailedEmailPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Email retry status */ + emailSent: Scalars['Boolean'] +} + +/** Valid payment risk levels */ +export enum RiskLevel { + /** An elevated risk level for a payment */ + Elevated = 'elevated', + /** The highest risk level for a payment */ + Highest = 'highest', + /** A normal risk level for a payment */ + Normal = 'normal', +} + +/** Represents a named role */ +export type Role = Node & { + __typename?: 'Role' + /** The role ID */ + _id: Scalars['ID'] + /** A unique name for the role */ + name: Scalars['String'] +} + +/** + * Wraps a list of `Roles`, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type RoleConnection = { + __typename?: 'RoleConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<RoleEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Role>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `Role` object */ +export type RoleEdge = NodeEdge & { + __typename?: 'RoleEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The role */ + node?: Maybe<Role> +} + +/** The fields by which you are allowed to sort any query that returns an `RoleConnection` */ +export enum RoleSortByField { + /** Role ID */ + Id = '_id', + /** Role name */ + Name = 'name', +} + +/** Input needed to select a fulfillment option for a single fulfillment group on a cart */ +export type SelectFulfillmentOptionForGroupInput = { + /** The cart to select this option for */ + cartId: Scalars['ID'] + /** The token for the cart, required if it is an anonymous cart */ + cartToken?: Maybe<Scalars['String']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The group to select this option for */ + fulfillmentGroupId: Scalars['ID'] + /** The fulfillment method ID from the option the shopper selected */ + fulfillmentMethodId: Scalars['ID'] +} + +/** The response from the `selectFulfillmentOptionForGroup` mutation */ +export type SelectFulfillmentOptionForGroupPayload = { + __typename?: 'SelectFulfillmentOptionForGroupPayload' + /** The updated Cart */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Describes which email should be sent a password reset link */ +export type SendResetAccountPasswordEmailInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The email address of the account to send reset email to */ + email: Scalars['String'] +} + +/** The response from the `sendResetAccountPasswordEmail` mutation */ +export type SendResetAccountPasswordEmailPayload = { + __typename?: 'SendResetAccountPasswordEmailPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The email address of the account to send reset email to */ + email: Scalars['String'] +} + +/** Defines which email address should be set as the default for which account */ +export type SetAccountDefaultEmailInput = { + /** The account ID, which defaults to the viewer account */ + accountId?: Maybe<Scalars['ID']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The email address to set as default */ + email: Scalars['Email'] +} + +/** The response from the `setAccountDefaultEmail` mutation */ +export type SetAccountDefaultEmailPayload = { + __typename?: 'SetAccountDefaultEmailPayload' + /** The account, with updated `emailRecords` */ + account?: Maybe<Account> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input for the `setEmailOnAnonymousCart` mutation call */ +export type SetEmailOnAnonymousCartInput = { + /** An anonymous cart ID */ + cartId: Scalars['ID'] + /** Provide the `cartToken` that was returned in the `CreateCartPayload` */ + cartToken: Scalars['String'] + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** + * The email address to associate with this cart. This address is used for order communication and + * other fulfillment purposes. + */ + email: Scalars['String'] +} + +/** The payload returned from the `setEmailOnAnonymousCart` mutation call */ +export type SetEmailOnAnonymousCartPayload = { + __typename?: 'SetEmailOnAnonymousCartPayload' + /** The modified cart */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input needed when setting the shipping address on a cart */ +export type SetShippingAddressOnCartInput = { + /** The shipping address */ + address: AddressInput + /** If set, this will be saved as the Address._id. Otherwise an ID will be generated. */ + addressId?: Maybe<Scalars['String']> + /** The cart to set shipping address on */ + cartId: Scalars['ID'] + /** The token for the cart, required if it is an anonymous cart */ + cartToken?: Maybe<Scalars['String']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** The response from the `setShippingAddressOnCart` mutation */ +export type SetShippingAddressOnCartPayload = { + __typename?: 'SetShippingAddressOnCartPayload' + /** The updated Cart */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input for `setTagHeroMedia` mutation */ +export type SetTagHeroMediaInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** File record document */ + fileRecord?: Maybe<Scalars['JSONObject']> + /** ID of tag to add the hero image record to */ + id: Scalars['ID'] + /** The shop that owns the tag */ + shopId: Scalars['ID'] +} + +/** Response payload for `setTagHeroMedia` mutation */ +export type SetTagHeroMediaPayload = { + __typename?: 'SetTagHeroMediaPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Tag the hero image was added to */ + tag: Tag +} + +/** Extra data for an order fulfillment group with type `shipping` */ +export type ShippingOrderFulfillmentGroupData = { + __typename?: 'ShippingOrderFulfillmentGroupData' + /** The address to ship to */ + shippingAddress: Address +} + +/** A shipping parcel */ +export type ShippingParcel = { + __typename?: 'ShippingParcel' + /** Containers */ + containers?: Maybe<Scalars['String']> + /** Distance unit */ + distanceUnit?: Maybe<DistanceUnit> + /** Height */ + height?: Maybe<Scalars['Float']> + /** Length */ + length?: Maybe<Scalars['Float']> + /** Mass unit */ + massUnit?: Maybe<MassUnit> + /** Weight */ + weight?: Maybe<Scalars['Float']> + /** Width */ + width?: Maybe<Scalars['Float']> +} + +/** Represents a Reaction shop */ +export type Shop = Node & { + __typename?: 'Shop' + /** The shop ID */ + _id: Scalars['ID'] + /** An the shop's default address */ + addressBook?: Maybe<Array<Maybe<Address>>> + /** Whether to allow user to checkout without creating an account */ + allowGuestCheckout?: Maybe<Scalars['Boolean']> + /** The base unit of length */ + baseUOL?: Maybe<Scalars['String']> + /** The base unit of Measure */ + baseUOM?: Maybe<Scalars['String']> + /** URLs for various shop assets in various sizes */ + brandAssets?: Maybe<ShopBrandAssets> + /** The default shop currency */ + currency: Currency + /** Default parcel size for this shop */ + defaultParcelSize?: Maybe<ShopParcelSize> + /** Shop description */ + description?: Maybe<Scalars['String']> + /** The shop's default email record */ + emails?: Maybe<Array<Maybe<EmailRecord>>> + /** Shop's keywords */ + keywords?: Maybe<Scalars['String']> + /** Shop default language */ + language: Scalars['String'] + /** Shop name */ + name: Scalars['String'] + /** Returns URLs for shop logos */ + shopLogoUrls?: Maybe<ShopLogoUrls> + /** Shop's type */ + shopType?: Maybe<Scalars['String']> + /** Shop's slug */ + slug?: Maybe<Scalars['String']> + /** Returns URLs for various storefront routes */ + storefrontUrls?: Maybe<StorefrontUrls> + /** Shop default timezone */ + timezone?: Maybe<Scalars['String']> + /** The shop's units of length */ + unitsOfLength?: Maybe<Array<Maybe<UnitOfLength>>> + /** The shop's units of measure */ + unitsOfMeasure?: Maybe<Array<Maybe<UnitOfMeasure>>> + /** Returns a list of groups for this shop, as a Relay-compatible connection. */ + groups?: Maybe<GroupConnection> + /** Returns a list of roles for this shop, as a Relay-compatible connection. */ + roles?: Maybe<RoleConnection> + /** Returns a paged list of tags for this shop */ + tags?: Maybe<TagConnection> + /** The default navigation tree for this shop */ + defaultNavigationTree?: Maybe<NavigationTree> + /** The ID of the shop's default navigation tree */ + defaultNavigationTreeId?: Maybe<Scalars['String']> +} + +/** Represents a Reaction shop */ +export type ShopGroupsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<GroupSortByField> +} + +/** Represents a Reaction shop */ +export type ShopRolesArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<RoleSortByField> +} + +/** Represents a Reaction shop */ +export type ShopTagsArgs = { + isTopLevel?: Maybe<Scalars['Boolean']> + shouldIncludeDeleted?: Maybe<Scalars['Boolean']> + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<TagSortByField> +} + +/** Represents a Reaction shop */ +export type ShopDefaultNavigationTreeArgs = { + language: Scalars['String'] + shouldIncludeSecondary?: Maybe<Scalars['Boolean']> +} + +/** URLs for various shop assets in various sizes */ +export type ShopBrandAssets = { + __typename?: 'ShopBrandAssets' + /** URLs for the navigation bar brand logo image */ + navbarBrandImage?: Maybe<ImageSizes> + /** Internal navigation bar brand logo image ID */ + navbarBrandImageId?: Maybe<Scalars['String']> +} + +/** + * Wraps a list of `Shops`, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type ShopConnection = { + __typename?: 'ShopConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<ShopEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Shop>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is an `Shop` object */ +export type ShopEdge = NodeEdge & { + __typename?: 'ShopEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The Shop */ + node?: Maybe<Shop> +} + +/** Shop logo URLs */ +export type ShopLogoUrls = { + __typename?: 'ShopLogoUrls' + /** The primary logo URL for this shop. Setting this overrides any uploaded logo. */ + primaryShopLogoUrl?: Maybe<Scalars['String']> +} + +/** Shop Logo URLs to provide for the updateShop mutation */ +export type ShopLogoUrlsInput = { + /** The primary logo URL for this shop. Setting this overrides any uploaded logo. */ + primaryShopLogoUrl?: Maybe<Scalars['String']> +} + +/** Parcel size */ +export type ShopParcelSize = { + __typename?: 'ShopParcelSize' + /** Parcel height */ + height?: Maybe<Scalars['Float']> + /** Parcel length */ + length?: Maybe<Scalars['Float']> + /** Parcel weight */ + weight?: Maybe<Scalars['Float']> + /** Parcel width */ + width?: Maybe<Scalars['Float']> +} + +/** Parcel size input */ +export type ShopParcelSizeInput = { + /** Parcel height */ + height?: Maybe<Scalars['Float']> + /** Parcel length */ + length?: Maybe<Scalars['Float']> + /** Parcel weight */ + weight?: Maybe<Scalars['Float']> + /** Parcel width */ + width?: Maybe<Scalars['Float']> +} + +/** + * App settings for a specific shop. Plugins extend the ShopSettings type to support + * whatever settings they need. + */ +export type ShopSettings = { + __typename?: 'ShopSettings' + /** A fake setting necessary until some plugin extends this with a real setting */ + doNotUse?: Maybe<Scalars['String']> + /** + * If there is no known inventory for a product configuration, this setting determines + * whether that product configuration can be sold and should appear to be available. + */ + canSellVariantWithoutInventory: Scalars['Boolean'] + /** + * If `false` no defined shipping rates will be used when fulfillment + * quotes are requested for a cart or order. A quick way to disable the entire + * `reaction-shipping-rates` plugin temporarily. + */ + isShippingRatesFulfillmentEnabled?: Maybe<Scalars['Boolean']> + /** The default value to use for `taxCode` property of a product */ + defaultTaxCode?: Maybe<Scalars['String']> + /** + * The name of the tax service to fall back to if the primary tax service is down. + * This will match the `name` field of one of the services returned by the `taxServices` + * query. + */ + fallbackTaxServiceName?: Maybe<Scalars['String']> + /** + * The name of the tax service to use for calculating taxes on carts and orders. + * This will match the `name` field of one of the services returned by the `taxServices` + * query. + */ + primaryTaxServiceName?: Maybe<Scalars['String']> + /** + * Whether a navigation item added to the navigation tree should be visible only to + * admins by default. + */ + shouldNavigationTreeItemsBeAdminOnly: Scalars['Boolean'] + /** + * Whether a navigation item added to the navigation tree should be + * public API/Storefront visible by default. + */ + shouldNavigationTreeItemsBePubliclyVisible: Scalars['Boolean'] + /** + * Whether a navigation item added to the navigation tree should be a secondary + * navigation item by default. + */ + shouldNavigationTreeItemsBeSecondaryNavOnly: Scalars['Boolean'] + /** This setting controls how often the sitemaps for the shop will be rebuilt */ + sitemapRefreshPeriod: Scalars['String'] +} + +/** + * Updates for app settings that are not shop specific. Plugins extend + * this input type to support whatever settings they need. All fields + * must be optional. + */ +export type ShopSettingsUpdates = { + /** Do not use this field */ + doNotUse?: Maybe<Scalars['String']> + /** + * If there is no known inventory for a product configuration, this setting determines + * whether that product configuration can be sold and should appear to be available. + */ + canSellVariantWithoutInventory?: Maybe<Scalars['Boolean']> + /** + * Set to `false` to prevent any defined shipping rates from being used when fulfillment + * quotes are requested for a cart or order. A quick way to disable the entire + * `reaction-shipping-rates` plugin temporarily. + */ + isShippingRatesFulfillmentEnabled?: Maybe<Scalars['Boolean']> + /** The default value to use for `taxCode` property of a product */ + defaultTaxCode?: Maybe<Scalars['String']> + /** + * Optionally, set the name of the tax service to fall back to if the primary tax service is down. + * This must match the `name` field of one of the services returned by the `taxServices` query. + */ + fallbackTaxServiceName?: Maybe<Scalars['String']> + /** + * Set the name of the tax service to use for calculating taxes on carts and orders. + * This will match the `name` field of one of the services returned by the `taxServices` + * query. There will be no taxes charged for any carts or orders if this is not set. + */ + primaryTaxServiceName?: Maybe<Scalars['String']> + /** + * Whether a navigation item added to the navigation tree should be visible only to + * admins by default. + */ + shouldNavigationTreeItemsBeAdminOnly?: Maybe<Scalars['Boolean']> + /** + * Whether a navigation item added to the navigation tree should be + * public API/Storefront visible by default. + */ + shouldNavigationTreeItemsBePubliclyVisible?: Maybe<Scalars['Boolean']> + /** + * Whether a navigation item added to the navigation tree should be a secondary + * navigation item by default. + */ + shouldNavigationTreeItemsBeSecondaryNavOnly?: Maybe<Scalars['Boolean']> + /** This setting controls how often the sitemaps for the shop will be rebuilt */ + sitemapRefreshPeriod?: Maybe<Scalars['String']> +} + +/** Inventory info for a specific product configuration. For inventory managed by the SimpleInventory plugin. */ +export type SimpleInventoryInfo = { + __typename?: 'SimpleInventoryInfo' + /** Whether to allow ordering this product configuration when there is insufficient quantity available */ + canBackorder?: Maybe<Scalars['Boolean']> + /** Current quantity of this product configuration in stock */ + inventoryInStock?: Maybe<Scalars['Int']> + /** + * Current quantity of this product configuration unavailable for ordering. This value is calculated + * by the system based on this product variant being in not-yet-approved orders. + */ + inventoryReserved?: Maybe<Scalars['Int']> + /** Whether the SimpleInventory plugin should manage inventory for this product configuration */ + isEnabled?: Maybe<Scalars['Boolean']> + /** + * The "low quantity" flag will be applied to this product configuration when the available quantity + * is at or below this threshold + */ + lowInventoryWarningThreshold?: Maybe<Scalars['Int']> + /** The product and chosen options this info applies to */ + productConfiguration: ProductConfiguration +} + +/** Generated sitemap XML for a single shop */ +export type Sitemap = { + __typename?: 'Sitemap' + /** Date created */ + createdAt: Scalars['Date'] + /** The sitemap handle */ + handle: Scalars['String'] + /** The shop ID */ + shopId: Scalars['String'] + /** The Sitemap XML content */ + xml: Scalars['String'] +} + +/** Holds metadata specific to a specific social network service */ +export type SocialMetadata = { + __typename?: 'SocialMetadata' + /** Default share message to use when sharing this product on this social network */ + message?: Maybe<Scalars['String']> + /** Which social network is this metadata for */ + service?: Maybe<SocialNetwork> +} + +/** The list of currently supported social network identifiers */ +export enum SocialNetwork { + /** Facebook */ + Facebook = 'facebook', + /** Google+ */ + Googleplus = 'googleplus', + /** Pinterest */ + Pinterest = 'pinterest', + /** Twitter */ + Twitter = 'twitter', +} + +/** The order in which the connection results should be sorted, based on the sortBy field. */ +export enum SortOrder { + /** ascending */ + Asc = 'asc', + /** descending */ + Desc = 'desc', +} + +/** Input for the splitOrderItem mutation */ +export type SplitOrderItemInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of the item order you want to split */ + itemId: Scalars['ID'] + /** The quantity that will be transferred to a new order item on the same fulfillment group. */ + newItemQuantity: Scalars['Int'] + /** ID of the order that has the item you want to split */ + orderId: Scalars['ID'] +} + +/** Response payload for the splitOrderItem mutation */ +export type SplitOrderItemPayload = { + __typename?: 'SplitOrderItemPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the new order item that was created */ + newItemId: Scalars['ID'] + /** The updated order */ + order: Order +} + +/** Storefront route URLs */ +export type StorefrontUrls = { + __typename?: 'StorefrontUrls' + /** Storefront Account Profile URL (can include `:accountId` in string) */ + storefrontAccountProfileUrl?: Maybe<Scalars['String']> + /** Storefront Home URL */ + storefrontHomeUrl?: Maybe<Scalars['String']> + /** Storefront login URL */ + storefrontLoginUrl?: Maybe<Scalars['String']> + /** Storefront single order URL (can include `:orderReferenceId` and `:orderToken` in string) */ + storefrontOrderUrl?: Maybe<Scalars['String']> + /** Storefront orders URL (can include `:accountId` in string) */ + storefrontOrdersUrl?: Maybe<Scalars['String']> +} + +/** Storefront route URLs to provide for the updateShop mutation */ +export type StorefrontUrlsInput = { + /** Storefront Account Profile URL (can include `:accountId` in string) */ + storefrontAccountProfileUrl?: Maybe<Scalars['String']> + /** Storefront Home URL */ + storefrontHomeUrl?: Maybe<Scalars['String']> + /** Storefront login URL */ + storefrontLoginUrl?: Maybe<Scalars['String']> + /** Storefront single order URL (can include `:orderReferenceId` and `:orderToken` in string) */ + storefrontOrderUrl?: Maybe<Scalars['String']> + /** Storefront orders URL (can include `:accountId` in string) */ + storefrontOrdersUrl?: Maybe<Scalars['String']> +} + +/** Data for a Stripe card payment */ +export type StripeCardPaymentData = { + __typename?: 'StripeCardPaymentData' + /** The Stripe charge ID */ + chargeId: Scalars['String'] + /** The Stripe customer ID, if a Stripe customer exists for this charge */ + customerId?: Maybe<Scalars['String']> +} + +export type Subscription = { + __typename?: 'Subscription' + /** A test subscription that returns an incremented number every 1 second for 10 seconds */ + tick: Scalars['Int'] +} + +/** An address suggestion returned from an address validation service */ +export type SuggestedAddress = { + __typename?: 'SuggestedAddress' + /** The street address / first line */ + address1: Scalars['String'] + /** Optional second line */ + address2?: Maybe<Scalars['String']> + /** City */ + city: Scalars['String'] + /** Country */ + country: Scalars['String'] + /** Postal code */ + postal: Scalars['String'] + /** Region. For example, a U.S. state */ + region: Scalars['String'] +} + +/** Defines a surcharge for surchargeById and surcharges query. */ +export type Surcharge = Node & { + __typename?: 'Surcharge' + /** The surcharge ID. */ + _id: Scalars['ID'] + /** Amount. */ + amount: Money + /** Attribute restrictions. */ + attributes?: Maybe<Array<Maybe<SurchargeAttributeRestrictions>>> + /** The date and time at which this surcharge was created */ + createdAt: Scalars['DateTime'] + /** Destination restrictions. */ + destination?: Maybe<SurchargeDestinationRestrictions> + /** Message translated into provided / default language. */ + message: Scalars['String'] + /** Messages provided with content and all languages */ + messagesByLanguage?: Maybe<Array<Maybe<SurchargeMessagesByLanguage>>> + /** Method IDs to apply this surcharge to. */ + methodIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** The shop ID */ + shopId: Scalars['ID'] + /** The type of this surcharge. Allowed types `surcharge`. */ + type: SurchargeTypeEnum + /** The date and time at which this surcharge was last updated */ + updatedAt?: Maybe<Scalars['DateTime']> +} + +/** Defines a surcharge for surchargeById and surcharges query. */ +export type SurchargeMessageArgs = { + language: Scalars['String'] +} + +/** Attribute Restrictions attached to a Surcharge */ +export type SurchargeAttributeRestrictions = { + __typename?: 'SurchargeAttributeRestrictions' + /** The operator to use for value comparison */ + operator?: Maybe<Scalars['String']> + /** The property to check */ + property?: Maybe<Scalars['String']> + /** The type of this property */ + propertyType?: Maybe<SurchargePropertyType> + /** The value to check for */ + value?: Maybe<Scalars['String']> +} + +/** Input to add a surcharge attribute restriction */ +export type SurchargeAttributeRestrictionsInput = { + /** The operator to use for value comparison */ + operator?: Maybe<Scalars['String']> + /** The property to check */ + property?: Maybe<Scalars['String']> + /** The type of this property */ + propertyType?: Maybe<SurchargePropertyType> + /** The value to check for */ + value?: Maybe<Scalars['String']> +} + +/** + * Wraps a list of `Surcharge`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type SurchargeConnection = { + __typename?: 'SurchargeConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<SurchargeEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Surcharge>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** Total count for all pages */ + totalCount: Scalars['Int'] +} + +/** + * Destination restrictions attached to a surcharge. If multiple of `country`, + * `region`, and `postal` are set, there is an AND relationship. + */ +export type SurchargeDestinationRestrictions = { + __typename?: 'SurchargeDestinationRestrictions' + /** Restrict for any of these destination countries */ + country?: Maybe<Array<Maybe<Scalars['String']>>> + /** Restrict for any of these destination postal codes */ + postal?: Maybe<Array<Maybe<Scalars['String']>>> + /** Restrict for any of these destination regions */ + region?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** Input to add a surcharge destination restriction */ +export type SurchargeDestinationRestrictionsInput = { + /** Restrict for any of these destination countries */ + country?: Maybe<Array<Maybe<Scalars['String']>>> + /** Restrict for any of these destination postal codes */ + postal?: Maybe<Array<Maybe<Scalars['String']>>> + /** Restrict for any of these destination regions */ + region?: Maybe<Array<Maybe<Scalars['String']>>> +} + +/** A connection edge in which each node is a `Surcharge` object */ +export type SurchargeEdge = { + __typename?: 'SurchargeEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The surcharge */ + node?: Maybe<Surcharge> +} + +/** Defines a surcharge. */ +export type SurchargeInput = { + /** Amount. */ + amount: Scalars['Float'] + /** Attribute restrictions. */ + attributes?: Maybe<Array<Maybe<SurchargeAttributeRestrictionsInput>>> + /** Destination restrictions. */ + destination?: Maybe<SurchargeDestinationRestrictionsInput> + /** Messages by language. */ + messagesByLanguage: Array<Maybe<MessagesByLanguageInput>> + /** Method IDs to apply this surcharge to. */ + methodIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** The type of this surcharge. Allowed types are `surcharge`. */ + type: SurchargeTypeEnum +} + +/** Object that includes translated content and language of translation */ +export type SurchargeMessagesByLanguage = { + __typename?: 'SurchargeMessagesByLanguage' + /** The message for this language */ + content: Scalars['String'] + /** The language code */ + language: Scalars['String'] +} + +/** A list of the possible property types for surcharges */ +export enum SurchargePropertyType { + /** Boolean */ + Bool = 'bool', + /** Float */ + Float = 'float', + /** Integer */ + Int = 'int', + /** String */ + String = 'string', +} + +/** Allowed values for surcharge `sortBy` parameter */ +export enum SurchargeSortByField { + /** The date the surcharge definition was created */ + CreatedAt = 'createdAt', +} + +/** Allowed values for surcharge type */ +export enum SurchargeTypeEnum { + /** Surcharge */ + Surcharge = 'surcharge', +} + +/** Represents Reaction System Infomation */ +export type SystemInformation = { + __typename?: 'SystemInformation' + /** Core api version */ + apiVersion: Scalars['String'] + /** Mongo version */ + mongoVersion: DatabaseInformation + /** Plugins installed with name, version information */ + plugins?: Maybe<Array<Maybe<Plugin>>> +} + +/** Represents a single tag */ +export type Tag = Node & + Deletable & { + __typename?: 'Tag' + /** The tag ID */ + _id: Scalars['ID'] + /** The date and time at which this tag was created */ + createdAt: Scalars['DateTime'] + /** A string of the title to be displayed on a Tag Listing Page */ + displayTitle?: Maybe<Scalars['String']> + /** A list of the IDs of top products in this tag */ + featuredProductIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** A string containing the hero image url for a Tag Listing Page */ + heroMediaUrl?: Maybe<Scalars['String']> + /** + * If `true`, this object should be considered deleted. Soft deleted objects are not + * returned in query results unless you explicitly ask for them. + */ + isDeleted: Scalars['Boolean'] + /** If `true`, this tag should be shown at the top level of the tag hierarchy */ + isTopLevel: Scalars['Boolean'] + /** If `true`, this tag's Tag Listing Page should be visible to the public */ + isVisible: Scalars['Boolean'] + /** Arbitrary additional metadata about this tag */ + metafields?: Maybe<Array<Maybe<Metafield>>> + /** The display name for the tag. This is unique within a given shop. */ + name: Scalars['String'] + /** The tag's position relative to other tags at the same level of the tag hierarchy */ + position?: Maybe<Scalars['Int']> + /** The shop to which this tag belongs */ + shop: Shop + /** A unique URL-safe string representing this tag for links */ + slug?: Maybe<Scalars['String']> + /** A list of the IDs of tags that have this tag as their parent in the tag hierarchy, in the user-defined order */ + subTagIds: Array<Maybe<Scalars['ID']>> + /** The date and time at which this tag was last updated */ + updatedAt: Scalars['DateTime'] + /** A paged list of tags that have this tag as their parent in the tag hierarchy. Currently only three levels are supported. */ + subTags?: Maybe<TagConnection> + } + +/** Represents a single tag */ +export type TagSubTagsArgs = { + after?: Maybe<Scalars['ConnectionCursor']> + before?: Maybe<Scalars['ConnectionCursor']> + first?: Maybe<Scalars['ConnectionLimitInt']> + last?: Maybe<Scalars['ConnectionLimitInt']> + offset?: Maybe<Scalars['Int']> + sortOrder?: Maybe<SortOrder> + sortBy?: Maybe<TagSortByField> +} + +/** + * Wraps a list of `Tags`, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type TagConnection = { + __typename?: 'TagConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<TagEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Tag>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `Tag` object */ +export type TagEdge = NodeEdge & { + __typename?: 'TagEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The tag */ + node?: Maybe<Tag> +} + +/** A tag product */ +export type TagProduct = { + __typename?: 'TagProduct' + /** The product id */ + _id: Scalars['ID'] + /** The date and time at which this CatalogProduct was created, which is when the related product was first published */ + createdAt: Scalars['DateTime'] + /** Position of the product */ + position?: Maybe<Scalars['Int']> + /** The title of the product */ + title?: Maybe<Scalars['String']> +} + +/** + * Wraps a list of `TagProduct`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type TagProductConnection = { + __typename?: 'TagProductConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<TagProductEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<TagProduct>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `TagProduct` object */ +export type TagProductEdge = { + __typename?: 'TagProductEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The tag product */ + node?: Maybe<TagProduct> +} + +/** The fields by which you are allowed to sort any query that returns a `TagConnection` */ +export enum TagSortByField { + /** Tag ID */ + Id = '_id', + /** Date and time the tag was created */ + CreatedAt = 'createdAt', + /** Tag name */ + Name = 'name', + /** Tag position */ + Position = 'position', + /** Date and time the tag was last updated */ + UpdatedAt = 'updatedAt', +} + +/** A tax code that may be used on a product to indicate proper taxation category */ +export type TaxCode = { + __typename?: 'TaxCode' + /** The code */ + code: Scalars['String'] + /** Short description of what types of products the code is for */ + label: Scalars['String'] +} + +/** A single calculated tax for a cart, order group, cart item, or order item */ +export type TaxRate = { + __typename?: 'TaxRate' + /** Tax rate ID */ + _id: Scalars['ID'] + /** An optional country code to limit where this tax is applied, in conjunction with `sourcing` field */ + country?: Maybe<Scalars['String']> + /** An optional postal code to limit where this tax is applied, in conjunction with `sourcing` field */ + postal?: Maybe<Scalars['String']> + /** The tax rate. For example, 0.05 for a 5% sales tax. */ + rate: Scalars['Float'] + /** An optional region (e.g., state) to limit where this tax is applied, in conjunction with `sourcing` field */ + region?: Maybe<Scalars['String']> + /** The shop to which this TaxRate belongs */ + shop: Shop + /** Whether the `country`, `postal`, and `region` filters apply to the origin address or the destination address */ + sourcing: TaxSource + /** An optional tax code, to apply this tax rate to only products that have this tax code */ + taxCode?: Maybe<Scalars['String']> +} + +/** + * Wraps a list of TaxRate`s, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type TaxRateConnection = { + __typename?: 'TaxRateConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<TaxRateEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<TaxRate>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `TaxRate` object */ +export type TaxRateEdge = { + __typename?: 'TaxRateEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The tax rate */ + node?: Maybe<TaxRate> +} + +/** A service registered by a tax plugin, that provides tax codes and calculations */ +export type TaxService = { + __typename?: 'TaxService' + /** Human-readable display name */ + displayName: Scalars['String'] + /** The tax service name. Any valid name that has been registered by a tax plugin. */ + name: Scalars['String'] + /** Name of the plugin that added the tax service */ + pluginName: Scalars['String'] +} + +/** Tax sources */ +export enum TaxSource { + /** Tax is applied when the destination matches the tax jurisdiction */ + Destination = 'destination', + /** Tax is applied when the origin matches the tax jurisdiction */ + Origin = 'origin', +} + +/** A summary of tax-related calculations for a cart or order group */ +export type TaxSummary = { + __typename?: 'TaxSummary' + /** The time at which taxes were last calculated for the cart or order group */ + calculatedAt: Scalars['DateTime'] + /** The name of the tax service that last calculated taxes for the cart or order group */ + calculatedByTaxServiceName?: Maybe<Scalars['String']> + /** A reference ID for the external system that calculated the taxes */ + referenceId?: Maybe<Scalars['String']> + /** Total tax calculated by the active tax service */ + tax: Money + /** Amount that was deemed subject to any taxes by the active tax service */ + taxableAmount: Money + /** Full list of all taxes that were calculated by the active tax service for the cart or order group */ + taxes: Array<Maybe<CalculatedTax>> +} + +/** Represents a Template */ +export type Template = Node & { + __typename?: 'Template' + /** The shop ID */ + _id: Scalars['ID'] + /** Email template language */ + language?: Maybe<Scalars['String']> + /** Email template name */ + name?: Maybe<Scalars['String']> + /** The shop that owns the template */ + shopId: Scalars['ID'] + /** Email template string */ + subject?: Maybe<Scalars['String']> + /** Email template body or html text */ + template?: Maybe<Scalars['String']> + /** Email template title */ + title?: Maybe<Scalars['String']> +} + +/** + * Wraps a list of Templates, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type TemplateConnection = { + __typename?: 'TemplateConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<TemplateEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Template>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a `Template` object */ +export type TemplateEdge = { + __typename?: 'TemplateEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The email template */ + node?: Maybe<Template> +} + +export type Tokens = { + __typename?: 'Tokens' + refreshToken?: Maybe<Scalars['String']> + accessToken?: Maybe<Scalars['String']> +} + +export type TwoFactorSecretKey = { + __typename?: 'TwoFactorSecretKey' + ascii?: Maybe<Scalars['String']> + base32?: Maybe<Scalars['String']> + hex?: Maybe<Scalars['String']> + qr_code_ascii?: Maybe<Scalars['String']> + qr_code_hex?: Maybe<Scalars['String']> + qr_code_base32?: Maybe<Scalars['String']> + google_auth_qr?: Maybe<Scalars['String']> + otpauth_url?: Maybe<Scalars['String']> +} + +export type TwoFactorSecretKeyInput = { + ascii?: Maybe<Scalars['String']> + base32?: Maybe<Scalars['String']> + hex?: Maybe<Scalars['String']> + qr_code_ascii?: Maybe<Scalars['String']> + qr_code_hex?: Maybe<Scalars['String']> + qr_code_base32?: Maybe<Scalars['String']> + google_auth_qr?: Maybe<Scalars['String']> + otpauth_url?: Maybe<Scalars['String']> +} + +/** Units of length */ +export type UnitOfLength = { + __typename?: 'UnitOfLength' + /** Whether this unit of length is the default */ + default?: Maybe<Scalars['Boolean']> + /** The name of the unit of length */ + label?: Maybe<Scalars['String']> + /** Unit of length */ + uol?: Maybe<Scalars['String']> +} + +/** Units of measure */ +export type UnitOfMeasure = { + __typename?: 'UnitOfMeasure' + /** Whether this unit of measure is the default */ + default?: Maybe<Scalars['Boolean']> + /** The name of the unit of measure */ + label?: Maybe<Scalars['String']> + /** Unit of measure */ + uom?: Maybe<Scalars['String']> +} + +/** Describes changes that should be applied to one of the addresses for an account */ +export type UpdateAccountAddressBookEntryInput = { + /** The account ID */ + accountId: Scalars['ID'] + /** The address ID */ + addressId: Scalars['ID'] + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** If present, make this address the default address of this type */ + type?: Maybe<AddressType> + /** The address changes to apply */ + updates: AddressInput +} + +/** The response from the `updateAccountAddressBookEntry` mutation */ +export type UpdateAccountAddressBookEntryPayload = { + __typename?: 'UpdateAccountAddressBookEntryPayload' + /** The updated address */ + address?: Maybe<Address> + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** The details for updating a group */ +export type UpdateAccountGroupInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The changes to apply to the group */ + group: UpdateGroupInput + /** The group ID */ + groupId: Scalars['ID'] + /** The ID of the shop this group belongs to */ + shopId?: Maybe<Scalars['ID']> +} + +/** The response from the `updateAccountGroup` mutation */ +export type UpdateAccountGroupPayload = { + __typename?: 'UpdateAccountGroupPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated group */ + group?: Maybe<Group> +} + +/** Describes an account update */ +export type UpdateAccountInput = { + /** The account ID, which defaults to the viewer account */ + accountId?: Maybe<Scalars['ID']> + /** Bio to display on profile */ + bio?: Maybe<Scalars['String']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The preferred currency code used by this account */ + currencyCode?: Maybe<Scalars['String']> + /** The first name of the person this account represents */ + firstName?: Maybe<Scalars['String']> + /** The preferred language (code) used by this account */ + language?: Maybe<Scalars['String']> + /** The last name of the person this account represents */ + lastName?: Maybe<Scalars['String']> + /** The full name of the person this account represents */ + name?: Maybe<Scalars['String']> + /** Some note about this account */ + note?: Maybe<Scalars['String']> + /** URL of picture to display on profile */ + picture?: Maybe<Scalars['String']> + /** Username */ + username?: Maybe<Scalars['String']> +} + +/** The response from the `updateAccount` mutation */ +export type UpdateAccountPayload = { + __typename?: 'UpdateAccountPayload' + /** The updated account */ + account: Account + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input for the `updateAddressValidationRule` mutation */ +export type UpdateAddressValidationRuleInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Country codes for which this service is enabled. `null` means all, while an empty array means none. */ + countryCodes?: Maybe<Array<Maybe<Scalars['String']>>> + /** ID of the rule you want to update */ + ruleId: Scalars['ID'] + /** + * The name of one of the installed validation services. Use `addressValidationServices` + * query to get a list, and then use the `name` field value from one of them. + */ + serviceName: Scalars['String'] + /** Shop ID of the rule you want to update. This is not something you can modify. */ + shopId: Scalars['ID'] +} + +/** Payload for the `updateAddressValidationRule` mutation */ +export type UpdateAddressValidationRulePayload = { + __typename?: 'UpdateAddressValidationRulePayload' + /** Updated address validation rule */ + addressValidationRule: AddressValidationRule + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +export type UpdateAdminUiAccessInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The account IDs to update */ + accountIds: Array<Maybe<Scalars['String']>> + /** The shop IDs to unassign or assign to the accounts */ + shopIds: Array<Maybe<Scalars['String']>> +} + +export type UpdateAdminUiAccessPayload = { + __typename?: 'UpdateAdminUIAccessPayload' + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The up to date account objects */ + accounts?: Maybe<Array<Maybe<Account>>> +} + +/** Input for the `updateCartItem` mutation */ +export type UpdateCartItemInput = { + /** The cart item ID */ + cartItemId: Scalars['ID'] + /** New absolute value for specified cart item's quantity. Not an incremental value. */ + quantity: Scalars['Int'] +} + +/** Input for the `updateCartItemsQuantity` mutation */ +export type UpdateCartItemsQuantityInput = { + /** The cart ID */ + cartId: Scalars['ID'] + /** If this cart is anonymous, provide the `cartToken` that was returned in the `CreateCartPayload` */ + cartToken?: Maybe<Scalars['String']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Array of cart item quantities to update. */ + items: Array<Maybe<UpdateCartItemInput>> +} + +/** The payload returned from the `updateCartItemsQuantity` mutation call */ +export type UpdateCartItemsQuantityPayload = { + __typename?: 'UpdateCartItemsQuantityPayload' + /** The modified cart */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Describes the input for updating a discount code */ +export type UpdateDiscountCodeInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The discount code to update */ + discountCode?: Maybe<DiscountCodeInput> + /** The ID of the discount code to update */ + discountCodeId: Scalars['ID'] + /** The shop ID of the discount code to update */ + shopId: Scalars['ID'] +} + +/** The response from the `updateDiscountCode` mutation */ +export type UpdateDiscountCodePayload = { + __typename?: 'UpdateDiscountCodePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated discount code */ + discountCode?: Maybe<DiscountCode> +} + +/** Input for the `updateFlatRateFulfillmentMethod` mutation */ +export type UpdateFlatRateFulfillmentMethodInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated method. Pass the whole updated method object without the ID. */ + method: FlatRateFulfillmentMethodInput + /** The ID of the flat rate fulfillment method you want to update */ + methodId: Scalars['ID'] + /** The shop that owns the method */ + shopId: Scalars['ID'] +} + +/** Response from the `updateFlatRateFulfillmentMethod` mutation */ +export type UpdateFlatRateFulfillmentMethodPayload = { + __typename?: 'UpdateFlatRateFulfillmentMethodPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated fulfillment method */ + method: FlatRateFulfillmentMethod +} + +/** Input for the `updateFlatRateFulfillmentRestriction` mutation */ +export type UpdateFlatRateFulfillmentRestrictionInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated flat rate fulfillment method restriction. Pass the whole updated restriction object without the ID. */ + restriction: FlatRateFulfillmentRestrictionInput + /** The ID of the flat rate fulfillment method restriction you want to update */ + restrictionId: Scalars['ID'] + /** The shop that owns the flat rate fulfillment method restriction */ + shopId: Scalars['ID'] +} + +/** Response from the `updateFlatRateFulfillmentMethod` mutation */ +export type UpdateFlatRateFulfillmentRestrictionPayload = { + __typename?: 'UpdateFlatRateFulfillmentRestrictionPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated flat rate fulfillment method restriction */ + restriction: FlatRateFulfillmentRestriction +} + +/** A request to update the available fulfillment options for a single fulfillment group */ +export type UpdateFulfillmentOptionsForGroupInput = { + /** The cart to update fulfillment options for */ + cartId: Scalars['ID'] + /** The token for the cart, required if it is an anonymous cart */ + cartToken?: Maybe<Scalars['String']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The group to update fulfillment options for */ + fulfillmentGroupId: Scalars['ID'] +} + +/** The response from the `updateFulfillmentOptionsForGroup` mutation */ +export type UpdateFulfillmentOptionsForGroupPayload = { + __typename?: 'UpdateFulfillmentOptionsForGroupPayload' + /** The updated Cart */ + cart: Cart + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> +} + +/** Input for the `updateGlobalSettings` mutation */ +export type UpdateGlobalSettingsInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Updated settings values. Only includes settings to be changed. */ + settingsUpdates: GlobalSettingsUpdates +} + +/** Response payload for the `updateGlobalSettings` mutation */ +export type UpdateGlobalSettingsPayload = { + __typename?: 'UpdateGlobalSettingsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Updated global settings */ + globalSettings: GlobalSettings +} + +/** Fields to update for an existing account group */ +export type UpdateGroupInput = { + /** A free text description of this group */ + description?: Maybe<Scalars['String']> + /** A unique name for the group */ + name?: Maybe<Scalars['String']> + /** A unique URL-safe string representing this group */ + slug?: Maybe<Scalars['String']> + /** A list of the account permissions implied by membership in this group */ + permissions?: Maybe<Array<Maybe<Scalars['String']>>> +} + +export type UpdateGroupsForAccountsInput = { + /** The account IDs */ + accountIds: Array<Maybe<Scalars['ID']>> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The group IDs */ + groupIds: Array<Maybe<Scalars['ID']>> +} + +export type UpdateGroupsForAccountsPayload = { + __typename?: 'UpdateGroupsForAccountsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The accounts that were modified */ + accounts: Array<Maybe<Account>> +} + +/** Input for the updateMediaRecordPriority mutation */ +export type UpdateMediaRecordPriorityInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of MediaRecord to update */ + mediaRecordId: Scalars['ID'] + /** New priority value */ + priority: Scalars['Int'] + /** ID of shop that owns this MediaRecord */ + shopId: Scalars['ID'] +} + +/** Response payload for the updateMediaRecordPriority mutation */ +export type UpdateMediaRecordPriorityPayload = { + __typename?: 'UpdateMediaRecordPriorityPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated MediaRecord */ + mediaRecord: MediaRecord +} + +/** Input for the `updateNavigationItem` mutation */ +export type UpdateNavigationItemInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the navigation item to update */ + id: Scalars['ID'] + /** The field updates to apply */ + navigationItem: NavigationItemInput + /** The ID of the shop navigation item belongs to */ + shopId: Scalars['ID'] +} + +/** Response payload for the `updateNavigationItem` mutation */ +export type UpdateNavigationItemPayload = { + __typename?: 'UpdateNavigationItemPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated navigation item */ + navigationItem?: Maybe<NavigationItem> +} + +/** Input for the `updateNavigationTree` mutation */ +export type UpdateNavigationTreeInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The ID of the navigation tree to update */ + id: Scalars['ID'] + /** The field updates to apply */ + navigationTree: NavigationTreeInput + /** The ID of the shop navigation item belongs to */ + shopId: Scalars['ID'] +} + +/** Response payload for the `updateNavigationTree` mutation */ +export type UpdateNavigationTreePayload = { + __typename?: 'UpdateNavigationTreePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated navigation tree */ + navigationTree?: Maybe<NavigationTree> +} + +/** Input for the updateOrderFulfillmentGroup mutation */ +export type UpdateOrderFulfillmentGroupInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of the order fulfillment group to update */ + orderFulfillmentGroupId: Scalars['ID'] + /** ID of the order to update */ + orderId: Scalars['ID'] + /** Set the current order fulfillment group status to this */ + status?: Maybe<Scalars['String']> + /** Set this as the current order fulfillment group shipment tracking reference */ + tracking?: Maybe<Scalars['String']> + /** Set this as the current order fulfillment group shipment tracking URL */ + trackingUrl?: Maybe<Scalars['String']> +} + +/** Response payload for the updateOrderFulfillmentGroup mutation */ +export type UpdateOrderFulfillmentGroupPayload = { + __typename?: 'UpdateOrderFulfillmentGroupPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated order */ + order: Order +} + +/** Input for the updateOrder mutation */ +export type UpdateOrderInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Set the order email to this */ + email?: Maybe<Scalars['String']> + /** ID of the order to update */ + orderId: Scalars['ID'] + /** Set the current order status to this */ + status?: Maybe<Scalars['String']> +} + +/** Response payload for the updateOrder mutation */ +export type UpdateOrderPayload = { + __typename?: 'UpdateOrderPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated order */ + order: Order +} + +/** Input for the `updateProduct` mutation */ +export type UpdateProductInput = { + /** Product input */ + product: ProductInput + /** ID of product to update */ + productId: Scalars['ID'] + /** ID of shop that owns the product to update */ + shopId: Scalars['ID'] +} + +/** Response payload of `updateProduct` mutation */ +export type UpdateProductPayload = { + __typename?: 'UpdateProductPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Updated product */ + product: Product +} + +/** Input for the `updateProductVariantField` mutation */ +export type UpdateProductVariantInput = { + /** ID of shop that owns the variant to update */ + shopId: Scalars['ID'] + /** Variant input */ + variant: ProductVariantInput + /** ID of variant to update */ + variantId: Scalars['ID'] +} + +/** Response payload of `updateProductVariantField` mutation */ +export type UpdateProductVariantPayload = { + __typename?: 'UpdateProductVariantPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Updated variant */ + variant: ProductVariant +} + +/** Input for the `updateProductVariantField` mutation */ +export type UpdateProductVariantPricesInput = { + /** Prices to update */ + prices: ProductVariantPricesInput + /** ID of shop that owns the variant to update */ + shopId: Scalars['ID'] + /** ID of variant to update */ + variantId: Scalars['ID'] +} + +/** Response payload of `updateProductVariantPricesField` mutation */ +export type UpdateProductVariantPricesPayload = { + __typename?: 'UpdateProductVariantPricesPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Updated variant */ + variant: ProductVariant +} + +/** Input for the `updateProductsVisibility` mutation */ +export type UpdateProductsVisibilityInput = { + /** The desired visibility */ + isVisible: Scalars['Boolean'] + /** Array of product ids to update */ + productIds: Array<Maybe<Scalars['ID']>> + /** ID of shop the products belong to */ + shopId: Scalars['ID'] +} + +/** Response payload for `updateProductsVisibility` mutation */ +export type UpdateProductsVisibilityPayload = { + __typename?: 'UpdateProductsVisibilityPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The number of products that were updated successfully */ + updatedCount?: Maybe<Scalars['Int']> +} + +/** Input parameters for the updateShop mutation */ +export type UpdateShopInput = { + /** An address book entry to set the primary shop's address */ + addressBook?: Maybe<Array<Maybe<AddressInput>>> + /** Whether to allow user to checkout without creating an account */ + allowGuestCheckout?: Maybe<Scalars['Boolean']> + /** The base unit of length */ + baseUOL?: Maybe<Scalars['String']> + /** The base unit of Measure */ + baseUOM?: Maybe<Scalars['String']> + /** ID of media record to be used as the brand asset */ + brandAssets?: Maybe<Scalars['ID']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The shop's currency */ + currency?: Maybe<Scalars['String']> + /** Default parcel size used for this shop */ + defaultParcelSize?: Maybe<ShopParcelSizeInput> + /** The shop's description */ + description?: Maybe<Scalars['String']> + /** The shops primary email address */ + emails?: Maybe<Array<Maybe<EmailRecordInput>>> + /** The shop's keywords */ + keywords?: Maybe<Scalars['String']> + /** The shop's language */ + language?: Maybe<Scalars['String']> + /** The shop's name */ + name?: Maybe<Scalars['String']> + /** The ID of the shop to update */ + shopId: Scalars['ID'] + /** Object of shop logo urls */ + shopLogoUrls?: Maybe<ShopLogoUrlsInput> + /** Shop's slug */ + slug?: Maybe<Scalars['String']> + /** Object of storefront routes urls */ + storefrontUrls?: Maybe<StorefrontUrlsInput> + /** The shop's timezone */ + timezone?: Maybe<Scalars['String']> +} + +/** The response from the `updateShop` mutation */ +export type UpdateShopPayload = { + __typename?: 'UpdateShopPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The shop which was updated */ + shop: Shop +} + +/** Input for the `updateShopSettings` mutation */ +export type UpdateShopSettingsInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Updated settings values. Only includes settings to be changed. */ + settingsUpdates: ShopSettingsUpdates + /** The ID of the shop to update some settings for */ + shopId: Scalars['ID'] +} + +/** Response payload for the `updateShopSettings` mutation */ +export type UpdateShopSettingsPayload = { + __typename?: 'UpdateShopSettingsPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** Updated shop settings */ + shopSettings: ShopSettings +} + +/** Input for the `updateSimpleInventory` mutation. In addition to `shopId`, at least one field to update is required. */ +export type UpdateSimpleInventoryInput = { + /** + * Whether to allow ordering this product configuration when there is insufficient quantity available. + * Set this to `true` or `false` if you want to update it. + */ + canBackorder?: Maybe<Scalars['Boolean']> + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Current quantity of this product configuration in stock. Set this to an integer if you want to update it. */ + inventoryInStock?: Maybe<Scalars['Int']> + /** + * Whether the SimpleInventory plugin should manage inventory for this product configuration. + * Set this to `true` or `false` if you want to update it. + */ + isEnabled?: Maybe<Scalars['Boolean']> + /** + * The "low quantity" flag will be applied to this product configuration when the available quantity + * is at or below this threshold. Set this to an integer if you want to update it. + */ + lowInventoryWarningThreshold?: Maybe<Scalars['Int']> + /** The product and chosen options this info applies to */ + productConfiguration: ProductConfigurationInput + /** Shop that owns the product */ + shopId: Scalars['ID'] +} + +/** Response payload for the `updateSimpleInventory` mutation */ +export type UpdateSimpleInventoryPayload = { + __typename?: 'UpdateSimpleInventoryPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated inventory info */ + inventoryInfo: SimpleInventoryInfo +} + +/** Input for the `updateSurcharge` mutation */ +export type UpdateSurchargeInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** The shop that owns the method */ + shopId: Scalars['ID'] + /** The updated surcharge. Pass the whole updated surcharge object without the ID. */ + surcharge: SurchargeInput + /** The ID of the flat rate fulfillment surcharge you want to update */ + surchargeId: Scalars['ID'] +} + +/** Response from the `updateFlatRateFulfillmentMethod` mutation */ +export type UpdateSurchargePayload = { + __typename?: 'UpdateSurchargePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated fulfillment surcharge */ + surcharge: Surcharge +} + +/** Input for `updateTag` mutation */ +export type UpdateTagInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** Title to display to customers */ + displayTitle?: Maybe<Scalars['String']> + /** A list of the IDs of top products in this tag */ + featuredProductIds?: Maybe<Array<Maybe<Scalars['ID']>>> + /** Hero media URL */ + heroMediaUrl?: Maybe<Scalars['String']> + /** ID of rule to modify */ + id: Scalars['ID'] + /** Whether the tag is visible */ + isVisible: Scalars['Boolean'] + /** Tag metafields */ + metafields?: Maybe<Array<Maybe<MetafieldInput>>> + /** Unique name of the tag */ + name: Scalars['String'] + /** The shop that owns the tag */ + shopId: Scalars['ID'] + /** The tag slug. If left blank, the name will be slugified and saved as the slug */ + slug?: Maybe<Scalars['String']> +} + +/** Response payload for `updateTag` mutation */ +export type UpdateTagPayload = { + __typename?: 'UpdateTagPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated tag */ + tag: Tag +} + +/** + * The input for updating a tax rate. Note that missing values will cause the field to be cleared, so + * send all optional fields with every request unless they aren't currently set or you intend to clear them. + */ +export type UpdateTaxRateInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** An optional country code to limit where this tax is applied based on destination address */ + country?: Maybe<Scalars['String']> + /** An optional postal code to limit where this tax is applied based on destination address */ + postal?: Maybe<Scalars['String']> + /** The tax rate. For example, 0.05 for a 5% sales tax. */ + rate: Scalars['Float'] + /** An optional region (e.g., state) to limit where this tax is applied based on destination address */ + region?: Maybe<Scalars['String']> + /** Shop ID */ + shopId: Scalars['ID'] + /** Whether the `country`, `postal`, and `region` filters apply to the origin address or the destination address */ + sourcing?: Maybe<TaxSource> + /** An optional tax code, to apply this tax rate to only products that have this tax code */ + taxCode?: Maybe<Scalars['String']> + /** ID of the tax rate you want to update */ + taxRateId: Scalars['ID'] +} + +/** The response from the `updateTaxRate` mutation */ +export type UpdateTaxRatePayload = { + __typename?: 'UpdateTaxRatePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated tax rate */ + taxRate: TaxRate +} + +/** Input for `updateTemplate` mutation */ +export type UpdateTemplateInput = { + /** An optional string identifying the mutation call, which will be returned in the response payload */ + clientMutationId?: Maybe<Scalars['String']> + /** ID of template to modify */ + id: Scalars['ID'] + /** The shop that owns the template */ + shopId: Scalars['ID'] + /** Email template string */ + subject?: Maybe<Scalars['String']> + /** Email template body or html text */ + template?: Maybe<Scalars['String']> + /** Email template title */ + title?: Maybe<Scalars['String']> +} + +/** Response payload for `updateTemplate` mutation */ +export type UpdateTemplatePayload = { + __typename?: 'UpdateTemplatePayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** The updated template */ + template: Template +} + +export type User = { + __typename?: 'User' + id: Scalars['ID'] + emails?: Maybe<Array<EmailRecord>> + username?: Maybe<Scalars['String']> +} + +export type UserInput = { + id?: Maybe<Scalars['ID']> + email?: Maybe<Scalars['String']> + username?: Maybe<Scalars['String']> +} + +export type Vendor = { + __typename?: 'Vendor' + /** The name of the vendor */ + name?: Maybe<Scalars['String']> +} + +/** + * Wraps an array of vendors, providing pagination cursors and information. + * + * For information about what Relay-compatible connections are and how to use them, see the following articles: + * - [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) + * - [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) + * - [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) + */ +export type VendorConnection = { + __typename?: 'VendorConnection' + /** The list of nodes that match the query, wrapped in an edge to provide a cursor string for each */ + edges?: Maybe<Array<Maybe<VendorEdge>>> + /** + * You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + * if you know you will not need to paginate the results. + */ + nodes?: Maybe<Array<Maybe<Vendor>>> + /** Information to help a client request the next or previous page */ + pageInfo: PageInfo + /** The total number of nodes that match your query */ + totalCount: Scalars['Int'] +} + +/** A connection edge in which each node is a String representing a vendor */ +export type VendorEdge = { + __typename?: 'VendorEdge' + /** The cursor that represents this node in the paginated results */ + cursor: Scalars['ConnectionCursor'] + /** The vendor */ + node?: Maybe<Vendor> +} + +/** Input for an `VerifySMTPEmailSettingsInput` */ +export type VerifySmtpEmailSettingsInput = { + /** The ID of the shop this setting belongs to */ + shopId: Scalars['ID'] +} + +/** Response payload for the verifySMTPEmailSettings mutation */ +export type VerifySmtpEmailSettingsInputPayload = { + __typename?: 'VerifySMTPEmailSettingsInputPayload' + /** The same string you sent with the mutation params, for matching mutation calls with their responses */ + clientMutationId?: Maybe<Scalars['String']> + /** True if the SMTP connection was made and authentication was successful. */ + isVerified: Scalars['Boolean'] +} + +/** A bulk write error type */ +export type WriteError = { + __typename?: 'WriteError' + /** The documentId(_id) on which the error occurred */ + documentId?: Maybe<Scalars['Int']> + /** Error message for a documentId */ + errorMsg?: Maybe<Scalars['String']> +} diff --git a/framework/reactioncommerce/schema.graphql b/framework/reactioncommerce/schema.graphql new file mode 100644 index 00000000..9f6232ad --- /dev/null +++ b/framework/reactioncommerce/schema.graphql @@ -0,0 +1,14307 @@ +""" +Represents a single user account +""" +type Account implements Node { + """ + The account ID + """ + _id: ID! + + """ + A list of physical or mailing addresses associated with this account + """ + addressBook( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + ): AddressConnection + + """ + A list of shops this user can administer with the admin UI + """ + adminUIShops: [Shop] + + """ + Bio to display on profile + """ + bio: String + + """ + The date and time at which this account was created + """ + createdAt: DateTime! + + """ + The preferred currency used by this account + """ + currency: Currency + + """ + A list of email records associated with this account + """ + emailRecords: [EmailRecord] + + """ + The first name of the person this account represents, if known + """ + firstName: String + + """ + The preferred language used by this account + """ + language: String + + """ + The last name of the person this account represents, if known + """ + lastName: String + + """ + Arbitrary additional metadata about this account + """ + metafields: [Metafield] + + """ + The full name of the person this account represents, if known + """ + name: String + + """ + Some note about this account + """ + note: String + + """ + URL of picture to display on profile + """ + picture: String + + """ + An object storing plugin-specific preferences for this account + """ + preferences: JSONObject + + """ + The primary email address for the account. This matches the address in `emailRecords` where `provides` is `default`. + """ + primaryEmailAddress: Email! + + """ + The date and time at which this account was last updated + """ + updatedAt: DateTime + + """ + The Identity user ID with which this account is associated + """ + userId: String! + + """ + Username + """ + username: String + + """ + A paged list of the account groups in which this account is listed + """ + groups( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, groups are sorted by when they were created, oldest first. Set this to sort by one of the other allowed fields + """ + sortBy: GroupSortByField = createdAt + ): GroupConnection +} + +""" +Wraps a list of `Accounts`, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type AccountConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [AccountEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Account] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is an `Account` object +""" +type AccountEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The account + """ + node: Account +} + +""" +The fields by which you are allowed to sort any query that returns an `AccountConnection` +""" +enum AccountSortByField { + """ + Account ID + """ + _id + + """ + Date and time at which this account was created + """ + createdAt + + """ + Date and time at which this account was last updated + """ + updatedAt +} + +""" +Defines a new Address and the account to which it should be added +""" +input AddAccountAddressBookEntryInput { + """ + The account ID + """ + accountId: ID! + + """ + The address to add + """ + address: AddressInput! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String +} + +""" +The response from the `addAccountAddressBookEntry` mutation +""" +type AddAccountAddressBookEntryPayload { + """ + The added address + """ + address: Address + + """ + The added address edge + """ + addressEdge: AddressEdge + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Defines a new Email and the account to which it should be added +""" +input AddAccountEmailRecordInput { + """ + The account ID, which defaults to the viewer account + """ + accountId: ID + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The email address to add + """ + email: Email! +} + +""" +The response from the `addAccountEmailRecord` mutation +""" +type AddAccountEmailRecordPayload { + """ + The account, with updated `emailRecords` + """ + account: Account + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Defines a group and account that should be linked +""" +input AddAccountToGroupInput { + """ + The account ID + """ + accountId: ID! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The group ID + """ + groupId: ID! +} + +""" +The response from the `addAccountToGroup` mutation +""" +type AddAccountToGroupPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated group + """ + group: Group +} + +""" +Input for the `addCartItems` mutation +""" +input AddCartItemsInput { + """ + The cart ID + """ + cartId: ID! + + """ + If this cart is anonymous, provide the `cartToken` that was returned in the `CreateCartPayload` + """ + cartToken: String + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Array of items to be added to the cart + """ + items: [CartItemInput]! +} + +""" +The payload returned from the `addCartItems` mutation call +""" +type AddCartItemsPayload { + """ + The modified cart. You should check `incorrectPriceFailures` and `minOrderQuantityFailures` for + information necessary to display errors to the shopper. Some items may not have been added. + """ + cart: Cart + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Clients should check to see if any items failed to be added due to the price not matching the current price. + In general, a user interface should display the correct current prices to the shopper, confirm that they still + want to add the items, and then call `createCart` or `addCartItems` to do so. + + Note that this field will always exist but may be an empty array if there were no failures of this type. + """ + incorrectPriceFailures: [IncorrectPriceFailureDetails]! + + """ + Clients should check to see if any items failed to be added due to quantity being below the minimum order + quantity defined for the product variant. In general, a user interface should display the minimum order + quantity to the shopper and allow them to add that quantity or greater. + + Note that this field will always exist but may be an empty array if there were no failures of this type. + """ + minOrderQuantityFailures: [MinOrderQuantityFailureDetails]! +} + +""" +Input for the addOrderFulfillmentGroup mutation +""" +input AddOrderFulfillmentGroupInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The order fulfillment group input, used to build the new group + """ + fulfillmentGroup: OrderFulfillmentGroupExistingOrderInput! + + """ + Optional list of order item IDs that should be moved from an existing group to the new group + """ + moveItemIds: [ID] + + """ + ID of the order that has the item you want to add the group to + """ + orderId: ID! +} + +""" +Response payload for the addOrderFulfillmentGroup mutation +""" +type AddOrderFulfillmentGroupPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + ID of the added fulfillment group + """ + newFulfillmentGroupId: ID! + + """ + The updated order + """ + order: Order! +} + +""" +Input for `addTag` mutation +""" +input AddTagInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Title to display to customers + """ + displayTitle: String + + """ + Hero media URL + """ + heroMediaUrl: String + + """ + Whether the tag is visible + """ + isVisible: Boolean! + + """ + Tag metafields + """ + metafields: [MetafieldInput] + + """ + Unique name of the tag + """ + name: String! + + """ + The shop that owns the tag + """ + shopId: ID! + + """ + The tag slug. If left blank, the name will be slugified and saved as the slug + """ + slug: String +} + +""" +Response payload for `addTag` mutation +""" +type AddTagPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The shop that owns the tag + """ + shopId: ID! + + """ + The newly-created tag + """ + tag: Tag! +} + +""" +Represents a physical or mailing address somewhere on Earth +""" +type Address { + """ + The address ID + """ + _id: ID + + """ + The street address / first line + """ + address1: String! + + """ + Optional second line + """ + address2: String + + """ + City + """ + city: String! + + """ + Optional company name, if it's a business address + """ + company: String + + """ + Country + """ + country: String! + + """ + The first name of a person at this address + This is an optional field to support legacy and third party platforms + We use fullName internally, and use first and last name fields to combine into a full name if needed + """ + firstName: String + + """ + The full name of a person at this address + """ + fullName: String! + + """ + Is this the default address for billing purposes? + """ + isBillingDefault: Boolean + + """ + Is this a commercial address? + """ + isCommercial: Boolean! + + """ + Is this the default address to use when selecting a shipping address at checkout? + """ + isShippingDefault: Boolean + + """ + The last name of a person at this address + This is an optional field to support legacy and third party platforms + We use fullName internally, and use first and last name fields to combine into a full name if needed + """ + lastName: String + + """ + Arbitrary additional metadata about this address + """ + metafields: [Metafield] + + """ + A phone number for someone at this address + """ + phone: String! + + """ + Postal code + """ + postal: String! + + """ + Region. For example, a U.S. state + """ + region: String! +} + +""" +Wraps a list of `Addresses`, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type AddressConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [AddressEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Address] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is an `Address` object +""" +type AddressEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The address + """ + node: Address +} + +""" +The details of an `Address` to be created or updated +""" +input AddressInput { + """ + The street address / first line + """ + address1: String! + + """ + Optional second line + """ + address2: String + + """ + Optionally, a name for this address (e.g. 'Home') to easily identify it in the future + """ + addressName: String + + """ + City + """ + city: String! + + """ + Optional company name, if it's a business address + """ + company: String + + """ + Country + """ + country: String! + + """ + The first name of a person at this address + This is an optional field to support legacy and third party platforms + We use fullName internally, and use first and last name fields to combine into a full name if needed + """ + firstName: String + + """ + The full name of a person at this address + """ + fullName: String! + + """ + Is this the default address for billing purposes? + """ + isBillingDefault: Boolean + + """ + Is this a commercial address? + """ + isCommercial: Boolean + + """ + Is this the default address to use when selecting a shipping address at checkout? + """ + isShippingDefault: Boolean + + """ + The last name of a person at this address + This is an optional field to support legacy and third party platforms + We use fullName internally, and use first and last name fields to combine into a full name if needed + """ + lastName: String + + """ + Arbitrary additional metadata about this address + """ + metafields: [MetafieldInput] + + """ + A phone number for someone at this address + """ + phone: String! + + """ + Postal code + """ + postal: String! + + """ + Region. For example, a U.S. state + """ + region: String! +} + +""" +A list of the possible types of `Address` +""" +enum AddressType { + """ + Address can be used for payment transactions and invoicing + """ + billing + + """ + Address can be used as a mailing address for sending physical items + """ + shipping +} + +""" +Details about an error that was the result of validating an address that is invalid +""" +type AddressValidationError { + """ + A longer, detailed error message suitable for showing in the user interface + """ + details: String + + """ + An identifier of the source of this error. These are not currently standardized. As long as your client understands it, any string is fine. + """ + source: String + + """ + A short error message suitable for showing in the user interface + """ + summary: String! + + """ + The error type. These are not currently standardized. As long as your client understands it, any string is fine. + """ + type: String! +} + +""" +The response from `Query.addressValidation` +""" +type AddressValidationResults { + """ + A list of suggested addresses. If the address is valid as is OR the address input is invalid OR + the shop is not configured to validate addresses, then this will be empty. + """ + suggestedAddresses: [SuggestedAddress]! + + """ + This may have information about the ways in which the provided address input is incomplete or invalid. + Show these errors in the address review user interface. + """ + validationErrors: [AddressValidationError]! +} + +""" +An address validation rule specifies which validation services should run for +which countries in each shop. +""" +type AddressValidationRule implements Node { + """ + The rule ID + """ + _id: ID! + + """ + Country codes for which this service is enabled + """ + countryCodes: [String] + + """ + The date and time at which this rule was created + """ + createdAt: DateTime! + + """ + The name of one of the installed validation services. Use `addressValidationServices` + query to get a list with more details about all installed services. + """ + serviceName: String! + + """ + ID of the shop to which this rule applies + """ + shopId: ID! + + """ + The date and time at which this rule was last updated + """ + updatedAt: DateTime! +} + +""" +Wraps a list of `AddressValidationRules`, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type AddressValidationRuleConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [AddressValidationRuleEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [AddressValidationRule] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `AddressValidationRule` object +""" +type AddressValidationRuleEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The address validation rule + """ + node: AddressValidationRule +} + +""" +The fields by which you are allowed to sort any query that returns an `AddressValidationRuleConnection` +""" +enum AddressValidationRuleSortByField { + """ + AddressValidationRule ID + """ + _id + + """ + Date and time at which the rule was created + """ + createdAt + + """ + Service name + """ + serviceName + + """ + Date and time at which the rule was last updated + """ + updatedAt +} + +""" +A single registered address validation service +""" +type AddressValidationService { + """ + Human-readable name to show operators + """ + displayName: String! + + """ + Unique name to serve as a key identifying this service + """ + name: String! + + """ + An optional list of all country codes that this address service supports. Null means all countries. + """ + supportedCountryCodes: [String] +} + +""" +Defines a surcharge that has been applied to a Cart or Order +""" +type AppliedSurcharge implements Node { + """ + The surcharge ID + """ + _id: ID! + + """ + The amount of the surcharge + """ + amount: Money! + + """ + The fulfillmentGroupId (for reference) + """ + fulfillmentGroupId: ID + + """ + The message to explain the surchage to customers, translated (if available) based on shop language + """ + message( + """ + The language in which you want the message. If no translation is available for this language, + it will be in the default language of the related shop. + """ + language: String! + ): String + + """ + The surchargeId from the surchages collection (for reference) + """ + surchargeDefinitionId: ID! +} + +""" +Input for an `ApplyDiscountCodeToCartInput` +""" +input ApplyDiscountCodeToCartInput { + """ + Cart to add discount to + """ + cartId: ID! + + """ + Discount code to add to cart + """ + discountCode: String! + + """ + Shop cart belongs to + """ + shopId: ID! + + """ + Cart token, if anonymous + """ + token: String +} + +""" +Response from the `applyDiscountCodeToCart` mutation +""" +type ApplyDiscountCodeToCartPayload { + """ + The updated cart with discount code applied + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input for the `approveOrderPayments` mutation +""" +input ApproveOrderPaymentsInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The order ID + """ + orderId: ID! + + """ + The IDs of one or more payments to approve for this order + """ + paymentIds: [ID]! + + """ + The ID of the shop that owns this order + """ + shopId: ID! +} + +""" +Response from the `approveOrderPayments` mutation +""" +type ApproveOrderPaymentsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated order + """ + order: Order! +} + +""" +Input for the archiveMediaRecord mutation +""" +input ArchiveMediaRecordInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of MediaRecord to archive + """ + mediaRecordId: ID! + + """ + ID of shop that owns this MediaRecord + """ + shopId: ID! +} + +""" +Response payload for the archiveMediaRecord mutation +""" +type ArchiveMediaRecordPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The archived MediaRecord + """ + mediaRecord: MediaRecord! +} + +""" +Input for the `archiveProducts` mutation +""" +input ArchiveProductVariantsInput { + """ + ID of shop that owns all variants you are archiving + """ + shopId: ID! + + """ + Array of IDs of variants to archive + """ + variantIds: [ID]! +} + +""" +Response payload of `archiveProductVariants` mutation +""" +type ArchiveProductVariantsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Array of newly archived variants + """ + variants: [ProductVariant]! +} + +""" +Input for the `archiveProducts` mutation +""" +input ArchiveProductsInput { + """ + Array of IDs of products to archive + """ + productIds: [ID]! + + """ + ID of shop that owns all products you are archiving + """ + shopId: ID! +} + +""" +Response payload of `archiveProducts` mutation +""" +type ArchiveProductsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Array of newly archived products + """ + products: [Product]! +} + +""" +An attribute restriction condition +""" +type AttributeRestrictions { + """ + The operator to use for value comparison + """ + operator: String! + + """ + The property to check + """ + property: String! + + """ + The type of this property + """ + propertyType: String! + + """ + The value to check for + """ + value: String! +} + +""" +Input to create an attribute restriction condition +""" +input AttributeRestrictionsInput { + """ + The operator to use for value comparison + """ + operator: String! + + """ + The property to check + """ + property: String! + + """ + The type of this property + """ + propertyType: String! + + """ + The value to check for + """ + value: String! +} + +input AuthenticateParamsInput { + access_token: String + access_token_secret: String + provider: String + password: String + user: UserInput + code: String +} + +""" +A single calculated tax for a cart, order group, cart item, or order item +""" +type CalculatedTax { + """ + Calculated tax ID + """ + _id: ID! + + """ + Jurisdiction ID. It is up to the tax service to determine if and how to use this. + """ + jurisdictionId: String + + """ + Did this tax match due to the order origin or the order destination? + """ + sourcing: TaxSource! + + """ + Amount of tax due + """ + tax: Money! + + """ + A human-readable display name for showing this tax to operators and customers in the UI + """ + taxName: String! + + """ + The tax rate used for this calculation + """ + taxRate: Rate! + + """ + Amount that was used for calculating the tax due + """ + taxableAmount: Money! +} + +""" +Input for the cancelOrderItem mutation +""" +input CancelOrderItemInput { + """ + Quantity to cancel. Must be equal to or less than the item quantity. + """ + cancelQuantity: Int! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of the item order you want to cancel + """ + itemId: ID! + + """ + ID of the order that has the item you want to cancel + """ + orderId: ID! + + """ + An optional free text reason for cancellation, which may be shown to operators + or to the user who placed the order. + """ + reason: String +} + +""" +Response payload for the cancelOrderItem mutation +""" +type CancelOrderItemPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated order + """ + order: Order! +} + +""" +Input for the `captureOrderPayments` mutation +""" +input CaptureOrderPaymentsInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The order ID + """ + orderId: ID! + + """ + The IDs of one or more payments to capture for this order + """ + paymentIds: [ID]! + + """ + The ID of the shop that owns this order + """ + shopId: ID! +} + +""" +Response from the `captureOrderPayments` mutation +""" +type CaptureOrderPaymentsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated order + """ + order: Order! +} + +""" +The cart holds selected items until order is placed. +""" +type Cart implements Node { + """ + The Cart ID + """ + _id: ID! + + """ + The account that owns the cart. Some carts are created for anonymous users. Anonymous carts have a null account. + Every account has exactly one cart per shop. + """ + account: Account + + """ + Holds all information collected for a cart during checkout + """ + checkout: Checkout + + """ + The date and time at which the cart was created, which is when the first item was added to it. + """ + createdAt: DateTime! + + """ + An email address that has been associated with the cart + """ + email: String + + """ + The date and time at which the cart will expire. Account carts usually do not expire, so they will have a null value here. + """ + expiresAt: DateTime + + """ + The items that have been added to the cart. A cart is not created until the first item is added. Items can be removed from a cart, and a cart is not deleted if all items are removed from it. Because all items may have been removed, this may be an empty array. + """ + items( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + By default, items are sorted by when they were added to the cart, newest first. Set this to sort by one of the other allowed fields + """ + sortBy: CartItemsSortByField = addedAt + ): CartItemConnection + + """ + If any products or variants become hidden or are deleted after they were added to this cart, they'll be + automatically moved from `items` to `missingItems`. Clients may want to use this to show an + "items that are no longer available" list to storefront users. + + If a product becomes visible again, the item will never be automatically moved from `missingItems` + back to `items`, but clients may want to provide a way for users to manually do this. + """ + missingItems: [CartItem] + + """ + If you integrate with third-party systems that require you to send the same ID for order + calculations as for cart calculations, you may use this ID, which is the same on a `cart` as on + the `order` placed from that cart. This ID can also be customized by plugins and is the best + ID to use if it is necessary to show a cart ID in the user interface. + """ + referenceId: String + + """ + The shop that owns the cart. + """ + shop: Shop! + + """ + Total quantity of all items in the cart + """ + totalItemQuantity: Int! + + """ + The date and time at which this cart was last updated. + """ + updatedAt: DateTime! + + """ + Surcharges applied to this cart + """ + surcharges: [AppliedSurcharge]! + + """ + A summary of calculated taxes for this cart. Null means "not able to calculate", + such as when no fulfillment method has been selected for some fulfillment groups. + """ + taxSummary: TaxSummary +} + +""" +A single item in a cart. The item contains information about an intended purchase. +""" +type CartItem implements Node { + """ + The cart item ID + """ + _id: ID! + + """ + " + The date and time at which this item was first added to the associated cart. + If an item is added, removed, and then added again, this will reflect the most recent addition. + However, if an item is added twice, the quantity will increase but this date will remain + the initial added date. + """ + addedAt: DateTime! + + """ + FUTURE. Additional attributes of the chosen item. For example, if this item is for a product, socks, where `blue` and `small` + options were chosen for some configurable attributes, then `color:blue` and `size:small` will be indicated here. + """ + attributes: [CartItemAttribute] + + """ + The current comparison (e.g., MSRP) price of the item + """ + compareAtPrice: Money + + """ + The date and time at which the cart item was created. If an item is added, removed, and then added again, + the original item is destroyed and this field will reflect the time it was created for the most recent addition. + """ + createdAt: DateTime! + + """ + The URLs for a picture of the item in various sizes + """ + imageURLs: ImageSizes + + """ + Arbitrary additional metadata about this cart item. + """ + metafields: [Metafield] + + """ + The selected variant optionTitle + """ + optionTitle: String + + """ + Packing information such as item weight, height, length, and depth. Used for calculating shipping rates. + """ + parcel: ShippingParcel + + """ + The current price of the item + """ + price: Money! + + """ + The price at which this item was listed when it was added to the cart + """ + priceWhenAdded: Money! + + """ + The product and chosen options + """ + productConfiguration: ProductConfiguration! + + """ + The product's slug + """ + productSlug: String + + """ + The list of tags that have been applied to this product + """ + productTags( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, tags are sorted by ID. Set this to sort by one of the other allowed fields + """ + sortBy: TagSortByField = _id + ): TagConnection + + """ + The type of product, used to display cart items differently + """ + productType: String + + """ + The product vendor + """ + productVendor: String + + """ + The quantity of this item that has been added to the cart. This must be a positive integer. Remove this `CartItem` from it's associated cart if you want `0` of this item. + """ + quantity: Int! + + """ + The shop associated with this cart item. + """ + shop: Shop! + + """ + The current price of the item multiplied by the quantity + """ + subtotal: Money! + + """ + A title for use in cart/orders that conveys the selected product's title + chosen options + """ + title: String! + + """ + The date and time at which this item was last updated + """ + updatedAt: DateTime! + + """ + The selected variant title + """ + variantTitle: String + + """ + The quantity of this item currently available to sell. + This number is updated when an order is placed by the customer. + This number does not include reserved inventory (i.e. inventory that has been ordered, but not yet processed by the operator). + This is most likely the quantity to display in the storefront UI. + """ + inventoryAvailableToSell: Int + + """ + True if this item is currently sold out but allows backorders. A storefront UI may use this + to decide to show a "Backordered" indicator. + """ + isBackorder: Boolean! + + """ + True if this item has a low available quantity (`inventoryAvailableToSell`) in stock. + A storefront UI may use this to decide to show a "Low Quantity" indicator. + """ + isLowQuantity: Boolean! + + """ + True if this item is currently sold out (`inventoryAvailableToSell` is 0). A storefront + UI may use this to decide to show a "Sold Out" indicator when `isBackorder` is not also true. + """ + isSoldOut: Boolean! + + """ + Is this a taxable item? + """ + isTaxable: Boolean! + + """ + Total tax calculated for this item + """ + tax: Money + + """ + The tax code for this item + """ + taxCode: String + + """ + Amount of subtotal that is taxable + """ + taxableAmount: Money + + """ + List of calculated taxes due for this item + """ + taxes: [CalculatedTax] +} + +""" +One attribute of a cart item +""" +type CartItemAttribute { + """ + The attribute label, e.g., Color + """ + label: String + + """ + The attribute value, e.g., Blue + """ + value: String +} + +""" +Wraps a list of `CartItem`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type CartItemConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [CartItemEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [CartItem] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `CartItem` object +""" +type CartItemEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The cart item + """ + node: CartItem +} + +""" +Information about an item to add to a cart +""" +input CartItemInput { + """ + Arbitrary additional metadata about this cart item. + """ + metafields: [MetafieldInput] + + """ + The price of this item, for validating that this matches the actual price in the system, + in case the client has stale data. + """ + price: MoneyInput! + + """ + The product and chosen options + """ + productConfiguration: ProductConfigurationInput! + + """ + The number of this item to add to the cart + """ + quantity: Int! +} + +""" +Allowed values for cart item sortBy parameter +""" +enum CartItemsSortByField { + """ + Cart item ID + """ + _id + + """ + Date and time at which the item was added to the cart + """ + addedAt +} + +""" +Supported cart reconciliation modes +""" +enum CartReconciliationMode { + """ + Delete the anonymous cart and use the account cart. + """ + keepAccountCart + + """ + Assign the anonymous cart to the account, and delete the account cart. + """ + keepAnonymousCart + + """ + Move all items from the anonymous cart into the account cart along with existing + account cart items. If the same item is in both carts, combine the quantities. + """ + merge +} + +""" +A summary of the totals for this cart +""" +type CartSummary { + """ + The total of all discounts applied, as a positive number + """ + discountTotal: Money! + + """ + The calculated tax-exclusive tax rate on all items and fulfillment prices (taxTotal / taxableAmount). + This may be null, and there is a difference between null and 0. Null means `not able to calculate`, + such as when no fulfillment method has been selected for some fulfillment groups. + """ + effectiveTaxRate: Rate + + """ + The total price of all chosen fulfillment methods. This may be null, and there is a difference + between null and 0. Null means `not able to calculate`, such as when no fulfillment method has + been selected for some fulfillment groups. + """ + fulfillmentTotal: Money + + """ + The combined prices of all cart items + """ + itemTotal: Money! + + """ + The total estimated tax that has not already been included in the item prices. This may be null, + and there is a difference between null and 0. Null means `not able to calculate`, such as when no + fulfillment methods have been selected or there is some other issue with the tax service. + """ + taxTotal: Money + + """ + The total amount that was deemed taxable by the tax service + """ + taxableAmount: Money! + + """ + The sum of `itemTotal`, `fulfillmentTotal`, and `taxTotal`, minus `discountTotal` + """ + total: Money! + + """ + The combined total of all surcharges. This may be null, and there is a difference + between null and 0. Null means `not able to calculate`, such as when no fulfillment method has + been selected for some fulfillment groups. + """ + surchargeTotal: Money +} + +""" +One product catalog for a particular shop +""" +type Catalog implements Node { + """ + The Catalog ID + """ + _id: ID! + + """ + The date and time at which this Catalog was first created + """ + createdAt: DateTime! + + """ + The shop to which this catalog belongs + """ + shop: Shop! + + """ + The date and time at which this Catalog was last updated + """ + updatedAt: DateTime! +} + +""" +A filter to be applied to a Catalog query +""" +input CatalogBooleanFilter { + """ + The name of the filter + """ + name: CatalogBooleanFilterName! + + """ + The filter value + """ + value: Boolean! +} + +""" +The list of currently supported top level Catalog props on which catalog items can be filtered. +""" +enum CatalogBooleanFilterName { + """ + isDeleted + """ + isDeleted + + """ + isVisible + """ + isVisible + + """ + isLowQuantity + """ + isLowQuantity + + """ + isSoldOut + """ + isSoldOut + + """ + isBackorder + """ + isBackorder +} + +""" +Catalog items are combined to create a catalog. Each item can represent a different type of content. +""" +interface CatalogItem { + """ + Item ID + """ + _id: ID! + + """ + Date and time at which the item was created + """ + createdAt: DateTime + + """ + Shop that owns the item + """ + shop: Shop! + + """ + Date and time at which the item was last updated + """ + updatedAt: DateTime +} + +""" +Wraps a list of `CatalogItem`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type CatalogItemConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [CatalogItemEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [CatalogItem] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +Represents a catalog item that displays some non-product content +""" +type CatalogItemContent implements CatalogItem & Node { + """ + The CatalogItemProduct ID + """ + _id: ID! + + """ + The date and time at which this CatalogItem was first created + """ + createdAt: DateTime! + + """ + The shop to which this catalog belongs + """ + shop: Shop! + + """ + The date and time at which this CatalogItem was last updated + """ + updatedAt: DateTime! +} + +""" +A connection edge in which each node is a `CatalogItem` object +""" +type CatalogItemEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The catalog item + """ + node: CatalogItem +} + +""" +Represents a catalog item that displays a product +""" +type CatalogItemProduct implements CatalogItem & Node { + """ + The CatalogItemProduct ID + """ + _id: ID! + + """ + The date and time at which this CatalogItem was first created, which is when the related product was first published + """ + createdAt: DateTime! + + """ + The catalog product + """ + product: CatalogProduct + + """ + The shop to which this catalog belongs + """ + shop: Shop! + + """ + The date and time at which this CatalogItem was last updated, which is when the related product was most recently published + """ + updatedAt: DateTime! +} + +""" +Allowed values for sorting catalog items +""" +enum CatalogItemSortByField { + """ + Sort by item ID + """ + _id + + """ + Sort by date and time at which the item was created + """ + createdAt + + """ + Sort in the shop-defined order for the tag filter + """ + featured + + """ + Sort by price + """ + minPrice + + """ + Sort by date and time at which the item was last updated + """ + updatedAt +} + +""" +Represents a product that has been published into a shop catalog. The related `Product` is the source of truth for +shop administrators, but that is then published to a catalog as a `CatalogProduct`, which is what should +be displayed to shoppers who browse that catalog. +""" +type CatalogProduct implements CatalogProductOrVariant & Node { + """ + The CatalogProduct ID. Do not assume that this is the same as the related product ID. See `productId` for that. + """ + _id: ID! + + """ + The product barcode value, if it has one + """ + barcode: String + + """ + The date and time at which this CatalogProduct was created, which is when the related product was first published + """ + createdAt: DateTime! + + """ + The full product description, which may have newline characters in it + """ + description: String + + """ + The height of the product, if it has physical dimensions + """ + height: Float + + """ + True if this product has been deleted. Typically, deleted products are not returned in queries. + """ + isDeleted: Boolean! + + """ + True if this product should be shown to shoppers. Typically, non-visible products are not returned in queries. + """ + isVisible: Boolean! + + """ + The length of the product, if it has physical dimensions + """ + length: Float + + """ + All media for this product and its variants + """ + media: [ImageInfo] + + """ + The product description to use for page `description` meta element in HTML + """ + metaDescription: String + + """ + Arbitrary additional metadata about this product + """ + metafields: [Metafield] + + """ + The minimum quantity that must be added to a cart + """ + minOrderQuantity: Int + + """ + The country of origin + """ + originCountry: String + + """ + Subtitle + """ + pageTitle: String + + """ + Dimensions and other information about the containers in which this product will be shipped + """ + parcel: ShippingParcel + + """ + The primary image + """ + primaryImage: ImageInfo + + """ + The related Product ID + """ + productId: ID! + + """ + An arbitrary product type value, such as from an external system + """ + productType: String + + """ + The shop to which this product belongs + """ + shop: Shop! + + """ + A stock keeping unit (SKU) identifier for this product + """ + sku: String + + """ + A URL-safe and human-readable string that uniquely identifies this product + """ + slug: String + + """ + Holds metadata specific to a specific social network service + """ + socialMetadata: [SocialMetadata] + + """ + When a shopper purchases this product, what types of fulfillment can they choose from? + """ + supportedFulfillmentTypes: [FulfillmentType]! + + """ + Product title + """ + title: String + + """ + The date and time at which this CatalogProduct was last updated, which is when the related product was most recently published + """ + updatedAt: DateTime! + + """ + A flat list of all variants for this product + """ + variants: [CatalogProductVariant] + + """ + The product vendor or manufacturer, for display + """ + vendor: String + + """ + The weight of the product on Earth, if it has physical dimensions + """ + weight: Float + + """ + The width of the product, if it has physical dimensions + """ + width: Float + + """ + The list of tag IDs that have been applied to this product + """ + tagIds: [ID] + + """ + The list of tags that have been applied to this product + """ + tags( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, tags are sorted by ID. Set this to sort by one of the other allowed fields + """ + sortBy: TagSortByField = _id + ): TagConnection + + """ + Price and related information, per currency + """ + pricing: [ProductPricingInfo]! + + """ + True if every purchasable variant of this product is sold out but allows backorders. A storefront UI may use this + to decide to show a "Backordered" indicator. + """ + isBackorder: Boolean! + + """ + True if at least one purchasable variant of this product has a low quantity in stock. A storefront UI may use this + to decide to show a "Low Quantity" indicator. + """ + isLowQuantity: Boolean! + + """ + True if every purchasable variant of this product is sold out. A storefront UI may use this + to decide to show a "Sold Out" indicator when `isBackorder` is not also true. + """ + isSoldOut: Boolean! +} + +""" +This interface represents the fields that are identical for both Products and Variants +""" +interface CatalogProductOrVariant { + """ + The product barcode value, if it has one + """ + barcode: String + + """ + The date and time at which this CatalogProduct was created, which is when the related product was first published + """ + createdAt: DateTime + + """ + The height of the product, if it has physical dimensions + """ + height: Float + + """ + The length of the product, if it has physical dimensions + """ + length: Float + + """ + Arbitrary additional metadata about this product + """ + metafields: [Metafield] + + """ + The minimum quantity that must be added to a cart + """ + minOrderQuantity: Int + + """ + The country of origin + """ + originCountry: String + + """ + The shop to which this product belongs + """ + shop: Shop! + + """ + A stock keeping unit (SKU) identifier for this product + """ + sku: String + + """ + Product or variant title + """ + title: String + + """ + The date and time at which this CatalogProduct was last updated, which is when the related product was most recently published + """ + updatedAt: DateTime + + """ + The weight of the product on Earth, if it has physical dimensions + """ + weight: Float + + """ + The width of the product, if it has physical dimensions + """ + width: Float +} + +""" +A variant of a catalog product +""" +type CatalogProductVariant implements CatalogProductOrVariant & Node { + """ + The CatalogProductVariant ID. Do not assume that this is the same as the related variant ID. See `variantId` for that. + """ + _id: ID! + + """ + The attribute label describes the category of variant, for example, `Color` or `Size`. + In most cases this will be the same for all variants at the same level. + """ + attributeLabel: String! + + """ + The product variant barcode value, if it has one + """ + barcode: String + + """ + The date and time at which this CatalogProductVariant was created, which is when the related product was first published + """ + createdAt: DateTime + + """ + The height of the product variant, if it has physical dimensions + """ + height: Float + + """ + The position of this variant among other variants at the same level of the product-variant-option hierarchy + """ + index: Int! + + """ + The length of the product, if it has physical dimensions + """ + length: Float + + """ + All media for this variant / option + """ + media: [ImageInfo] + + """ + Arbitrary additional metadata about this product + """ + metafields: [Metafield] + + """ + The minimum quantity that must be added to a cart + """ + minOrderQuantity: Int + + """ + A short title to use for product detail select lists + """ + optionTitle: String + + """ + Child variants, if any + """ + options: [CatalogProductVariant] + + """ + The country of origin + """ + originCountry: String + + """ + The primary image of this variant / option + """ + primaryImage: ImageInfo + + """ + The shop to which this product variant belongs + """ + shop: Shop! + + """ + A stock keeping unit (SKU) identifier for this product + """ + sku: String + + """ + The full variant title for use on cart, checkout, and order summaries and on invoices. + This fully describes the configured variant. For example, if this is an option with + `optionTitle` `Large`, its parent variant has `optionTitle` `Red`, and the product + `title` is `Fancy T-Shirt`, then this `title` will be something like `Fancy T-Shirt - Red - Large`. + """ + title: String + + """ + The date and time at which this CatalogProduct was last updated, which is when the related product was most recently published + """ + updatedAt: DateTime + + """ + The related Variant ID + """ + variantId: ID! + + """ + The weight of the product on Earth, if it has physical dimensions + """ + weight: Float + + """ + The width of the product, if it has physical dimensions + """ + width: Float + + """ + Price and related information, per currency + """ + pricing: [ProductPricingInfo]! + + """ + True for a purchasable variant if an order containing this variant will be accepted even when there is insufficient + available inventory (`inventoryAvailableToSell`) to fulfill it immediately. For non-purchasable variants, this is true if at least one purchasable + child variant can be backordered. A storefront UI may use this in combination with `inventoryAvailableToSell` to + decide whether to show or enable an "Add to Cart" button. + """ + canBackorder: Boolean! + + """ + The quantity of this item currently available to sell. + This number is updated when an order is placed by the customer. + This number does not include reserved inventory (i.e. inventory that has been ordered, but not yet processed by the operator). + If this is a variant, this number is created by summing all child option inventory numbers. + This is most likely the quantity to display in the storefront UI. + """ + inventoryAvailableToSell: Int + + """ + The quantity of this item currently in stock. + This number is updated when an order is processed by the operator. + This number includes all inventory, including reserved inventory (i.e. inventory that has been ordered, but not yet processed by the operator). + If this is a variant, this number is created by summing all child option inventory numbers. + This is most likely just used as a reference in the operator UI, and not displayed in the storefront UI. + """ + inventoryInStock: Int + + """ + True for a purchasable variant if it is sold out but allows backorders. For non-purchasable variants, this is + true if every purchasable child variant is sold out but allows backorders. A storefront UI may use this + to decide to show a "Backordered" indicator. + """ + isBackorder: Boolean! + + """ + True for a purchasable variant if it has a low available quantity (`inventoryAvailableToSell`) in stock. + For non-purchasable variants, this is true if at least one purchasable child variant has a low available + quantity in stock. A storefront UI may use this to decide to show a "Low Quantity" indicator. + """ + isLowQuantity: Boolean! + + """ + True for a purchasable variant if it is sold out (`inventoryAvailableToSell` is 0). For non-purchasable + variants, this is true if every purchasable child variant is sold out. A storefront UI may use this + to decide to show a "Sold Out" indicator when `isBackorder` is not also true. + """ + isSoldOut: Boolean! + + """ + Is sales tax charged on this item? + """ + isTaxable: Boolean! + + """ + An optional code which, if understood by the active tax service for the shop, determines how this product should be taxed + """ + taxCode: String + + """ + A description to use for the tax line item on an invoice + """ + taxDescription: String +} + +""" +Holds all information collected for a cart during checkout +""" +type Checkout { + """ + One or more fulfillment groups, for example, mapping certain items to certain shipping addresses + """ + fulfillmentGroups: [FulfillmentGroup]! + + """ + A summary of the totals for this cart + """ + summary: CartSummary! +} + +""" +Input for the `cloneProductVariants` mutation +""" +input CloneProductVariantsInput { + """ + ID of shop that owns all product variants you want to clone + """ + shopId: ID! + + """ + Array of IDs of variants to clone + """ + variantIds: [ID]! +} + +""" +Response payload of `cloneProductVariants` mutation +""" +type CloneProductVariantsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Array of newly cloned product variants + """ + variants: [ProductVariant]! +} + +""" +Input for the `cloneProducts` mutation +""" +input CloneProductsInput { + """ + Array of IDs of products to clone + """ + productIds: [ID]! + + """ + ID of shop that owns all products you are cloning + """ + shopId: ID! +} + +""" +Response payload of `cloneProducts` mutation +""" +type CloneProductsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Array of newly cloned products + """ + products: [Product]! +} + +""" +An opaque string that identifies a particular result within a connection, +allowing you to request a subset of results before or after that result. +""" +scalar ConnectionCursor + +""" +An integer between 1 and 50, inclusive. Values less than 1 become 1 and +values greater than 50 become 50. +""" +scalar ConnectionLimitInt + +""" +The details for creating a group +""" +input CreateAccountGroupInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The group to create + """ + group: GroupInput! + + """ + The ID of the shop this group belongs to + """ + shopId: ID +} + +""" +The response from the `createAccountGroup` mutation +""" +type CreateAccountGroupPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The new group + """ + group: Group +} + +""" +Defines the account which should be created +""" +input CreateAccountInput { + """ + Bio to display on profile + """ + bio: String + + """ + Email record to create account with + """ + emails: [EmailRecordInput]! + + """ + Name to display on profile + """ + name: String + + """ + URL of picture to display on profile + """ + picture: String + + """ + The ID of the shop this account will belong to + """ + shopId: ID! + + """ + The userID account was created from create a new account from + """ + userId: ID! + + """ + Username + """ + username: String +} + +""" +The response from the `createAccount` mutation +""" +type CreateAccountPayload { + """ + The added account + """ + account: Account + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input for the `createAddressValidationRule` mutation +""" +input CreateAddressValidationRuleInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Country codes for which this service is enabled. `null` means all, while an empty array means none. + """ + countryCodes: [String] + + """ + The name of one of the installed validation services. Use `addressValidationServices` + query to get a list, and then use the `name` field value from one of them. + """ + serviceName: String! + + """ + ID of the shop to which this rule applies + """ + shopId: ID! +} + +""" +Payload for the `createAddressValidationRule` mutation +""" +type CreateAddressValidationRulePayload { + """ + Created address validation rule + """ + addressValidationRule: AddressValidationRule! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +The input necessary to create a cart +""" +input CreateCartInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Array of items to add to new cart. + """ + items: [CartItemInput]! + + """ + ShopId association for the cart. + """ + shopId: ID! +} + +""" +The payload returned from the `createCart` mutation call +""" +type CreateCartPayload { + """ + The created cart, if at least one item could be added. Otherwise null, and you should check + `incorrectPriceFailures` and `minOrderQuantityFailures` for information necessary to display + errors to the shopper. + """ + cart: Cart + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Clients should check to see if any items failed to be added due to the price not matching the current price. + In general, a user interface should display the correct current prices to the shopper, confirm that they still + want to add the items, and then call `createCart` or `addCartItems` to do so. + + Note that this field will always exist but may be an empty array if there were no failures of this type. + """ + incorrectPriceFailures: [IncorrectPriceFailureDetails]! + + """ + Clients should check to see if any items failed to be added due to quantity being below the minimum order + quantity defined for the product variant. In general, a user interface should display the minimum order + quantity to the shopper and allow them to add that quantity or greater. + + Note that this field will always exist but may be an empty array if there were no failures of this type. + """ + minOrderQuantityFailures: [MinOrderQuantityFailureDetails]! + + """ + If no identity token is provided with the request, then this mutation will create an anonymous cart. All + anonymous carts have a token associated with them, which allows the client that created the cart to access + that cart in the future. This is the only time this token is returned, so clients must store this securely + in some type of local storage solution, and then send it along with all future anonymous cart queries and + mutations. + """ + token: String +} + +""" +Describes the input for creating a discount code +""" +input CreateDiscountCodeInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The discount code to update + """ + discountCode: DiscountCodeInput + + """ + The shop ID of the discount code to update + """ + shopId: ID! +} + +""" +The response from the `createDiscountCode` mutation +""" +type CreateDiscountCodePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created discount code + """ + discountCode: DiscountCode +} + +""" +Input for the `createFlatRateFulfillmentMethod` mutation +""" +input CreateFlatRateFulfillmentMethodInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + This defines the flat rate fulfillment method that you want to create + """ + method: FlatRateFulfillmentMethodInput! + + """ + The shop to create this flat rate fulfillment method for + """ + shopId: ID! +} + +""" +Response from the `createFlatRateFulfillmentMethod` mutation +""" +type CreateFlatRateFulfillmentMethodPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created fulfillment method + """ + method: FlatRateFulfillmentMethod! +} + +""" +Input for the `CreateFlatRateFulfillmentRestriction` mutation +""" +input CreateFlatRateFulfillmentRestrictionInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + This defines the flat rate fulfillment method restriction that you want to create + """ + restriction: FlatRateFulfillmentRestrictionInput! + + """ + The shop to create this flat rate fulfillment method restriction for + """ + shopId: ID! +} + +""" +Response from the `CreateFlatRateFulfillmentRestriction` mutation +""" +type CreateFlatRateFulfillmentRestrictionPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created flat rate fulfillment method restriction + """ + restriction: FlatRateFulfillmentRestriction! +} + +""" +Input for the createMediaRecord mutation +""" +input CreateMediaRecordInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The media record to insert, with related file data already fully uploaded to temporary storage + """ + mediaRecord: MediaRecordInput! + + """ + ID of shop that owns this MediaRecord + """ + shopId: ID! +} + +""" +Response payload for the createMediaRecord mutation +""" +type CreateMediaRecordPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created MediaRecord + """ + mediaRecord: MediaRecord! +} + +""" +Input for the `createNavigationItem` mutation +""" +input CreateNavigationItemInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The navigation item to create + """ + navigationItem: NavigationItemInput! +} + +""" +Response payload for the `createNavigationItem` mutation +""" +type CreateNavigationItemPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created navigation item + """ + navigationItem: NavigationItem +} + +""" +Input for the `createNavigationTree` mutation +""" +input CreateNavigationTreeInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The draft navigation items that make up this tree + """ + draftItems: [NavigationTreeItemInput] + + """ + The name of the tree, for operator display purposes + """ + name: String! + + """ + The ID of the shop this navigation tree belongs to + """ + shopId: ID! +} + +""" +Response payload for the `createNavigationTree` mutation +""" +type CreateNavigationTreePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created navigation tree + """ + navigationTree: NavigationTree! +} + +""" +Input for the `createProduct` mutation +""" +input CreateProductInput { + """ + Product input + """ + product: ProductInput + + """ + ID of shop product will belong to + """ + shopId: ID! + + """ + Set to false if you do not want to auto-create the first variant of the product + """ + shouldCreateFirstVariant: Boolean = true +} + +""" +Response payload of `createProduct` mutation +""" +type CreateProductPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created product + """ + product: Product! +} + +""" +Input for the `createProductVariant` mutation +""" +input CreateProductVariantInput { + """ + ID of product variant belongs to + """ + productId: ID! + + """ + ID of shop product variant will belong to + """ + shopId: ID! + + """ + Variant input + """ + variant: ProductVariantInput +} + +""" +Response payload of `createProductVariant` mutation +""" +type CreateProductVariantPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created product variant + """ + variant: ProductVariant! +} + +""" +Input for the cancelOrderItem mutation +""" +input CreateRefundInput { + """ + Amount to cancel. Must be equal to or less than the remaining non-refunded payment amount for this payment method. + """ + amount: Float! + + """ + ID of the order that has the item you want to cancel + """ + orderId: ID! + + """ + ID of the payment that you want to refund + """ + paymentId: ID! + + """ + An optional free text reason for refund, which may be shown to operators + or to the user who requested the refund. + """ + reason: String +} + +""" +Response payload for the createRefund mutation +""" +type CreateRefundPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated order + """ + order: Order! +} + +""" +Input parameters for the `createShop` mutation +""" +input CreateShopInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Currency in which all money values should be assumed to be. Default is `USD`. + """ + currencyCode: String + + """ + Default language for translation and localization. Default is `en`. + """ + defaultLanguage: String + + """ + Primary timezone. Default is `US/Pacific` + """ + defaultTimezone: String + + """ + An optional description of the shop, intended for only admins to see + """ + description: String + + """ + A unique name for the shop + """ + name: String! + + """ + The shop type. Default is `primary`, but there may be only one primary shop. + """ + type: String +} + +""" +The response from the `createShop` mutation +""" +type CreateShopPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The shop which was created + """ + shop: Shop! +} + +""" +Input for the `CreateSurcharge` mutation +""" +input CreateSurchargeInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The shop to create this surcharge for + """ + shopId: ID! + + """ + This defines the surcharge that you want to create + """ + surcharge: SurchargeInput! +} + +""" +Response from the `CreateSurcharge` mutation +""" +type CreateSurchargePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created surcharge + """ + surcharge: Surcharge! +} + +""" +The input for creating a tax rate +""" +input CreateTaxRateInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + An optional country code to limit where this tax is applied based on destination address + """ + country: String + + """ + An optional postal code to limit where this tax is applied based on destination address + """ + postal: String + + """ + The tax rate. For example, 0.05 for a 5% sales tax. + """ + rate: Float! + + """ + An optional region (e.g., state) to limit where this tax is applied based on destination address + """ + region: String + + """ + Shop ID + """ + shopId: ID! + + """ + Whether the `country`, `postal`, and `region` filters apply to the origin address or the destination address + """ + sourcing: TaxSource = destination + + """ + An optional tax code, to apply this tax rate to only products that have this tax code + """ + taxCode: String +} + +""" +The response from the `createTaxRate` mutation +""" +type CreateTaxRatePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The created tax rate + """ + taxRate: TaxRate! +} + +input CreateUserInput { + username: String + email: String + password: String +} + +type CreateUserResult { + userId: ID + loginResult: LoginResult +} + +""" +Input for the createdAt database field +""" +input CreatedAtInput { + """ + Start date, inclusive + """ + gte: DateTime + + """ + End date, inclusive + """ + lte: DateTime +} + +""" +Represents one type of currency +""" +type Currency implements Node { + """ + ID + """ + _id: ID! + + """ + Currency code + """ + code: String! + + """ + Decimal symbol + """ + decimal: String + + """ + Format string + """ + format: String! + + """ + Exchange rate from shop default currency, if known + """ + rate: Float + + """ + The decimal scale used by this currency + """ + scale: Int + + """ + Currency symbol + """ + symbol: String! + + """ + Thousands separator symbol + """ + thousand: String +} + +""" +The product price or price range for a specific currency +""" +type CurrencyExchangeProductPricingInfo { + """ + A comparison price value, usually MSRP. If `price` is null, this will also be null. That is, + only purchasable variants will have a `compareAtPrice`. + """ + compareAtPrice: Money + + """ + The code for the currency these pricing details applies to + """ + currency: Currency! + + """ + UI should display this price. If a product has multiple potential prices depending on selected + variants and options, then this is a price range string such as "$3.95 - $6.99". It includes the currency + symbols. + """ + displayPrice: String! + + """ + The price of the most expensive possible variant+option combination + """ + maxPrice: Float! + + """ + The price of the least expensive possible variant+option combination + """ + minPrice: Float! + + """ + For variants with no options and for options, this will always be set to a price. For variants + with options and products, this will be `null`. There must be a price for a variant to be + added to a cart or purchased. Otherwise you would instead add one of its child options to a cart. + """ + price: Float +} + +""" +Represents Mongo Database information +""" +type DatabaseInformation { + """ + Version of database + """ + version: String! +} + +""" +A date string, such as 2007-12-03, compliant with the `full-date` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar Date + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar DateTime + +""" +Objects implementing the Deletable support soft deletion +""" +interface Deletable { + """ + If true, this object should be considered deleted. Soft deleted objects are not + returned in query results unless you explicitly ask for them. + """ + isDeleted: Boolean! +} + +""" +Input for the `deleteAddressValidationRule` mutation +""" +input DeleteAddressValidationRuleInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of the rule you want to delete + """ + ruleId: ID! + + """ + Shop ID of the rule you want to delete + """ + shopId: ID! +} + +""" +Payload for the `deleteAddressValidationRule` mutation +""" +type DeleteAddressValidationRulePayload { + """ + Deleted address validation rule + """ + addressValidationRule: AddressValidationRule! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Describes the input for removing a discount code +""" +input DeleteDiscountCodeInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The discount code ID + """ + discountCodeId: ID! + + """ + Shop ID + """ + shopId: ID! +} + +""" +The response from the `deleteDiscountCode` mutation +""" +type DeleteDiscountCodePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The deleted discount code + """ + discountCode: DiscountCode +} + +""" +Input for the `deleteFlatRateFulfillmentMethod` mutation +""" +input DeleteFlatRateFulfillmentMethodInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The ID of the flat rate fulfillment method you want to delete + """ + methodId: ID! + + """ + The shop that owns the method + """ + shopId: ID! +} + +""" +Response from the `deleteFlatRateFulfillmentMethod` mutation +""" +type DeleteFlatRateFulfillmentMethodPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The removed fulfillment method + """ + method: FlatRateFulfillmentMethod! +} + +""" +Input for the `deleteFlatRateFulfillmentRestriction` mutation +""" +input DeleteFlatRateFulfillmentRestrictionInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The ID of the flat rate fulfillment method restriction you want to delete + """ + restrictionId: ID! + + """ + The shop that owns the flat rate fulfillment method restriction + """ + shopId: ID! +} + +""" +Response from the `deleteFlatRateFulfillmentRestriction` mutation +""" +type DeleteFlatRateFulfillmentRestrictionPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The removed flat rate fulfillment method restriction + """ + restriction: FlatRateFulfillmentRestriction! +} + +""" +Input for the deleteMediaRecord mutation +""" +input DeleteMediaRecordInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of MediaRecord to delete + """ + mediaRecordId: ID! + + """ + ID of shop that owns this MediaRecord + """ + shopId: ID! +} + +""" +Response payload for the deleteMediaRecord mutation +""" +type DeleteMediaRecordPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The deleted MediaRecord + """ + mediaRecord: MediaRecord! +} + +""" +Input for the `deleteNavigationItem` mutation +""" +input DeleteNavigationItemInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The ID of the navigation item to delete + """ + id: ID! + + """ + The ID of the shop navigation item belongs to + """ + shopId: ID! +} + +""" +Response payload for the `deleteNavigationItem` mutation +""" +type DeleteNavigationItemPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The deleted navigation item + """ + navigationItem: NavigationItem +} + +""" +Input for the `deleteSurcharge` mutation +""" +input DeleteSurchargeInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The shop that owns the method + """ + shopId: ID! + + """ + The ID of the flat rate fulfillment method you want to delete + """ + surchargeId: ID! +} + +""" +Response from the `deleteSurcharge` mutation +""" +type DeleteSurchargePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The removed fulfillment method + """ + surcharge: Surcharge! +} + +""" +Describes the input for removing a tax rate +""" +input DeleteTaxRateInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Shop ID + """ + shopId: ID! + + """ + The tax rate ID + """ + taxRateId: ID! +} + +""" +The response from the `deleteTaxRate` mutation +""" +type DeleteTaxRatePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The deleted tax rate + """ + taxRate: TaxRate! +} + +""" +Destination restriction conditions. If multiple of `country`, +`region`, and `postal` are set, there is an AND relationship. +""" +type DestinationRestrictions { + """ + Restrict for any of these destination countries + """ + country: [String] + + """ + Restrict for any of these destination postal codes + """ + postal: [String] + + """ + Restrict for any of these destination regions + """ + region: [String] +} + +""" +Input for a destination restriction condition +""" +input DestinationRestrictionsInput { + """ + Restrict for any of these destination countries + """ + country: [String] + + """ + Restrict for any of these destination postal codes + """ + postal: [String] + + """ + Restrict for any of these destination regions + """ + region: [String] +} + +""" +Discount code calculation +""" +type DiscountCalculation { + """ + Discount code calculation method + """ + method: DiscountCalculationMethod +} + +""" +Input type for discount calculation +""" +input DiscountCalculationInput { + """ + Discount code calculation method + """ + method: DiscountCalculationMethod +} + +""" +Discount calculation types +""" +enum DiscountCalculationMethod { + """ + Store credit + """ + credit + + """ + Discount of order + """ + discount + + """ + Sale on an item + """ + sale + + """ + Discount to shipping + """ + shipping +} + +""" +A discount code +""" +type DiscountCode { + """ + Discount code ID + """ + _id: ID! + + """ + How the discount should be applied + """ + calculation: DiscountCalculation + + """ + Discount Code + """ + code: String! + + """ + Discount code conditions + """ + conditions: DiscountConditions + + """ + Description to describe the discount code + """ + description: String + + """ + Discount is allowed to be string or number. + it's a formula value (could be shipping code) + """ + discount: String + + """ + Discount method type + """ + discountMethod: DiscountMethod + + """ + Label to describe the code + """ + label: String + + """ + The shop to which this DiscountCode belongs to + """ + shop: Shop! + + """ + History of transactions + """ + transactions: [DiscountTransaction] +} + +""" +Wraps a list of DiscountCode`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type DiscountCodeConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [DiscountCodeEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [DiscountCode] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `DiscountCode` object +""" +type DiscountCodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The discount code + """ + node: DiscountCode +} + +""" +Input type for filters to be applied to an discount codes list +""" +input DiscountCodeFilterInput { + """ + Keywords typed by the user in the search input field + """ + searchField: String +} + +""" +Input type for a discount code +""" +input DiscountCodeInput { + """ + How the discount should be applied + """ + calculation: DiscountCalculationInput + + """ + Discount Code + """ + code: String! + + """ + Discount code conditions + """ + conditions: DiscountConditionsInput + + """ + Description to describe the discount code + """ + description: String + + """ + Discount is allowed to be string or number. + it's a formula value (could be shipping code) + """ + discount: String + + """ + Discount method type + """ + discountMethod: DiscountMethod + + """ + Label to describe the code + """ + label: String + + """ + History of transactions + """ + transactions: [DiscountTransactionInput] +} + +""" +The conditions an order must meet for a discount code to be applied +""" +type DiscountConditionOrder { + """ + Order date range end + """ + endDate: DateTime + + """ + Maximum order value + """ + max: Float + + """ + Minimum order value + """ + min: Float! + + """ + Order date range start + """ + startDate: DateTime +} + +""" +Discount order conditions input type +""" +input DiscountConditionOrderInput { + """ + Order date range end + """ + endDate: DateTime + + """ + Maximum order value + """ + max: Float + + """ + Minimum order value + """ + min: Float! + + """ + Order date range start + """ + startDate: DateTime +} + +""" +Conditions for a discount code to be applied +""" +type DiscountConditions { + """ + Account Limit + """ + accountLimit: Int + + """ + Audience that may apply this discount code + """ + audience: [String] + + """ + Is this discount code enabled + """ + enabled: Boolean! + + """ + Order conditions + """ + order: DiscountConditionOrder + + """ + Permissions that may apply this discount code + """ + permissions: [String] + + """ + Products that may apply this discount code + """ + products: [String] + + """ + Number of times this code may be redeemed. + Setting to 100 means the first 100 customers may apply this code. + Setting this value to 0 will allow this code to be applied an infinite number of times. + """ + redemptionLimit: Int + + """ + Tags that may be apply this discount code + """ + tags: [String] +} + +""" +Discount conditions input type +""" +input DiscountConditionsInput { + """ + Account Limit + """ + accountLimit: Int + + """ + Audience that may apply this discount code + """ + audience: [String] + + """ + Is this discount code enabled + """ + enabled: Boolean! + + """ + Order conditions + """ + order: DiscountConditionOrderInput + + """ + Permissions that may apply this discount code + """ + permissions: [String] + + """ + Products that may apply this discount code + """ + products: [String] + + """ + Number of times this code may be redeemed. + Setting to 100 means the first 100 customers may apply this code. + Setting this value to 0 will allow this code to be applied an infinite number of times. + """ + redemptionLimit: Int + + """ + Tags that may be apply this discount code + """ + tags: [String] +} + +""" +Discount method types +""" +enum DiscountMethod { + """ + Code type + """ + code + + """ + Rate type + """ + rate +} + +""" +Transaction history for a discount code +""" +type DiscountTransaction { + """ + Date the code was applied + """ + appliedAt: DateTime + + """ + Cart id + """ + cartId: String! + + """ + User id + """ + userId: String! +} + +""" +Discount transation input type +""" +input DiscountTransactionInput { + """ + Date the code was applied + """ + appliedAt: DateTime + + """ + Cart id + """ + cartId: String! + + """ + User id + """ + userId: String! +} + +""" +Distance units +""" +enum DistanceUnit { + """ + Centimeter + """ + cm + + """ + Foot + """ + ft + + """ + Inch + """ + in +} + +""" +A string email address +""" +scalar Email + +type EmailRecord { + address: String + verified: Boolean +} + +""" +A confirmable email record +""" +input EmailRecordInput { + """ + The actual email address + """ + address: Email + + """ + The services provided by this address + """ + provides: String + + """ + Has this address been verified? + """ + verified: Boolean +} + +""" +Input for the `enablePaymentMethodForShop` mutation +""" +input EnablePaymentMethodForShopInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + True to enable it or false to disable it + """ + isEnabled: Boolean! + + """ + The name of the payment method to enable or disable + """ + paymentMethodName: String! + + """ + The ID of the shop for which this payment method should be enabled or disabled + """ + shopId: ID! +} + +""" +Response payload for the `enablePaymentMethodForShop` mutation +""" +type EnablePaymentMethodForShopPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The full list of payment methods for the shop + """ + paymentMethods: [PaymentMethod]! +} + +""" +Data for an example IOU payment +""" +type ExampleIOUPaymentData { + """ + The name of the IOU payer entered by the shopper + """ + fullName: String! +} + +""" +Data for an example IOU payment method +""" +type ExampleIOUPaymentMethodData { + """ + Example + """ + example: String! +} + +""" +Do not use this +""" +type FakeData { + """ + Do not use this + """ + doNotUse: String +} + +""" +Defines a fulfillment method that has a fixed price. This type is provided by the `flat-rate` fulfillment plugin. +""" +type FlatRateFulfillmentMethod implements Node { + """ + The flat rate fulfillment method ID + """ + _id: ID! + + """ + The cost of this fulfillment method to the shop, if you track this + """ + cost: Float + + """ + The fulfillment types for which this method may be used. For example, `shipping` or `digital`. + """ + fulfillmentTypes: [FulfillmentType]! + + """ + The group to which this method belongs + """ + group: String! + + """ + A fixed price to charge for handling costs when this fulfillment method is selected for an order + """ + handling: Float! + + """ + Include this as a fulfillment option shown to shoppers during checkout? + """ + isEnabled: Boolean! + + """ + The name of this method, for display in the user interface + """ + label: String! + + """ + The name of this method, a unique identifier + """ + name: String! + + """ + A fixed price to charge for fulfillment costs when this fulfillment method is selected for an order + """ + rate: Float! + + """ + The shop to which this fulfillment method belongs + """ + shop: Shop! +} + +""" +Wraps a list of FlatRateFulfillmentMethods`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type FlatRateFulfillmentMethodConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [FlatRateFulfillmentMethodEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [FlatRateFulfillmentMethod] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `FlatRateFulfillmentMethod` object +""" +type FlatRateFulfillmentMethodEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The fulfillment method + """ + node: FlatRateFulfillmentMethod +} + +""" +Defines a fulfillment method that has a fixed price. This type is provided by the `flat-rate` fulfillment plugin. +""" +input FlatRateFulfillmentMethodInput { + """ + The cost of this fulfillment method to the shop, if you track this + """ + cost: Float + + """ + The fulfillment types for which this method may be used. For example, `shipping` or `digital`. + """ + fulfillmentTypes: [FulfillmentType]! + + """ + The group to which this method belongs + """ + group: String! + + """ + A fixed price to charge for handling costs when this fulfillment method is selected for an order + """ + handling: Float! + + """ + Include this as a fulfillment option shown to shoppers during checkout? + """ + isEnabled: Boolean! + + """ + The name of this method, for display in the user interface + """ + label: String! + + """ + The name of this method, a unique identifier + """ + name: String! + + """ + A fixed price to charge for fulfillment costs when this fulfillment method is selected for an order + """ + rate: Float! +} + +""" +Defines a flat rate fulfillment method restriction. +""" +type FlatRateFulfillmentRestriction implements Node { + """ + The restriction ID. + """ + _id: ID! + + """ + Attribute restrictions. Multiple attribute restrictions are evaluated with AND. If both destination and attribute restrictions are present, they evaluate with AND. + """ + attributes: [AttributeRestrictions] + + """ + Destination restrictions. If multiple destination restrictions are present, the most localized is the only one evaluated (i.e. evaluate postal if present, then region if present, then country). If both destination and attribute restrictions are present, they evaluate with AND. + """ + destination: DestinationRestrictions + + """ + Method IDs to apply this restriction to. If none, applies to all methods as a universal restriction. + """ + methodIds: [ID] + + """ + The shop ID + """ + shopId: ID! + + """ + The type of this restriction. Allowed types are `allow` or `deny`. + """ + type: RestrictionTypeEnum! +} + +""" +Wraps a list of `FlatRateFulfillmentRestriction`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type FlatRateFulfillmentRestrictionConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [FlatRateFulfillmentRestrictionEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [FlatRateFulfillmentRestriction] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `FlatRateFulfillmentRestriction` object +""" +type FlatRateFulfillmentRestrictionEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The flat rate fulfillment restriction + """ + node: FlatRateFulfillmentRestriction +} + +""" +Defines the input for a flat rate fulfillment method restriction. +""" +input FlatRateFulfillmentRestrictionInput { + """ + Attribute restrictions. Multiple attribute restrictions are evaluated with AND. If both destination and attribute restrictions are present, they evaluate with AND. + """ + attributes: [AttributeRestrictionsInput] + + """ + Destination restrictions. If multiple destination restrictions are present, the most localized is the only one evaluated (i.e. evaluate postal if present, then region if present, then country). If both destination and attribute restrictions are present, they evaluate with AND. + """ + destination: DestinationRestrictionsInput + + """ + Method IDs to apply this restriction to. If none, applies to all methods as a universal restriction. + """ + methodIds: [ID] + + """ + The type of this restriction. Allowed types are `allow` or `deny`. + """ + type: RestrictionTypeEnum! +} + +""" +Allowed values for `FlatRateFulfillmentRestriction` sortBy parameter +""" +enum FlatRateFulfillmentRestrictionSortByField { + """ + Date the restriction was created + """ + createdAt +} + +""" +Information needed by the selected fulfillment method to properly fulfill the order +""" +type FulfillmentData { + """ + The mailing address to which this fulfillment group should be shipped + """ + shippingAddress: Address +} + +""" +Links one or more cart items to fulfillment data. The most common example is having one FulfillmentGroup +per shipping address. +""" +type FulfillmentGroup implements Node { + """ + The fulfillment ID + """ + _id: ID! + + """ + The list of fulfillment options from which the shopper may choose. This list is created by taking + the full list of registered fulfillment methods, keeping only those that match the fulfillment `type` + of this group, and then calculating a price and handlingPrice for each based on the `items` in this group. + """ + availableFulfillmentOptions: [FulfillmentOption]! + + """ + Information needed by the fulfillment type to properly fulfill the order + """ + data: FulfillmentData + + """ + The items that are included in this fulfillment group + """ + items: [CartItem]! + + """ + The fulfillment method selected by a shopper for this group, with its associated price + """ + selectedFulfillmentOption: FulfillmentOption + + """ + The shipping address collected for this group, if relevant + """ + shippingAddress: Address + + """ + The shop that owns the items in this group and is responsible for fulfillment + """ + shop: Shop! + + """ + The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital` + """ + type: FulfillmentType! +} + +""" +A single fulfillment method. Fulfillment methods are shown to shoppers along with a quote for them, +and the shopper chooses one method per fulfillment group per cart during checkout. +""" +type FulfillmentMethod implements Node { + """ + The fulfillment method ID + """ + _id: ID! + + """ + A carrier name + """ + carrier: String + + """ + The name of this method, for display in the user interface + """ + displayName: String! + + """ + The fulfillment types for which this method may be used. For example, `shipping` or `digital`. + """ + fulfillmentTypes: [FulfillmentType]! + + """ + The group to which this method belongs + """ + group: String + + """ + The name of this method, a unique identifier + """ + name: String! +} + +""" +A fulfillment option for a cart fulfillment group, which is a method with an associated price +""" +type FulfillmentOption { + """ + The fulfillment method this pricing is for + """ + fulfillmentMethod: FulfillmentMethod + + """ + The additional amount charged for handling + """ + handlingPrice: Money! + + """ + The base price charged + """ + price: Money! +} + +""" +Allowed fulfillment types +""" +enum FulfillmentType { + """ + An order will be fulfilled digitally, such as by sending a download link + """ + digital + + """ + An order will be fulfilled by the customer picking it up + """ + pickup + + """ + An order will be fulfilled by the seller shipping it to the customer + """ + shipping +} + +""" +Input for the `generateSitemaps` mutation +""" +input GenerateSitemapsInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The ID of the shop to generate sitemap for + """ + shopId: ID! +} + +""" +Response for the `generateSitemaps` mutation +""" +type GenerateSitemapsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Whether the sitemap generation job was successfully scheduled + """ + wasJobScheduled: Boolean! +} + +""" +App settings that are not shop specific. Plugins extend the GlobalSettings type to support +whatever settings they need. +""" +type GlobalSettings { + """ + A fake setting necessary until some plugin extends this with a real setting + """ + doNotUse: String +} + +""" +Updates for app settings that are not shop specific. Plugins extend +this input type to support whatever settings they need. All fields +must be optional. +""" +input GlobalSettingsUpdates { + """ + Do not use this field + """ + doNotUse: String +} + +input GrantOrRevokeAdminUIAccessInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The account ID to update + """ + accountId: String! + + """ + The shop IDs to unassign or assign to the accounts + """ + shopId: String! +} + +type GrantOrRevokeAdminUIAccessPayload { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The up to date account object + """ + account: Account +} + +""" +Represents an account group +""" +type Group implements Node { + """ + The group ID + """ + _id: ID! + + """ + The date and time at which this group was created + """ + createdAt: DateTime! + + """ + The account that created this group + """ + createdBy: Account + + """ + A free text description of this group + """ + description: String + + """ + A unique name for the group + """ + name: String! + + """ + The shop to which this group belongs + """ + shop: Shop + + """ + A unique URL-safe string representing this group + """ + slug: String! + + """ + The date and time at which this group was last updated + """ + updatedAt: DateTime! + + """ + A list of the account permissions implied by membership in this group + """ + permissions: [String] +} + +""" +Wraps a list of `Groups`, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type GroupConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [GroupEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Group] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `Group` object +""" +type GroupEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The group + """ + node: Group +} + +""" +A group definition +""" +input GroupInput { + """ + A free text description of this group + """ + description: String + + """ + A unique name for the group + """ + name: String! + + """ + A unique URL-safe string representing this group + """ + slug: String + + """ + A list of the account permissions implied by membership in this group + """ + permissions: [String] +} + +""" +The fields by which you are allowed to sort any query that returns an `GroupConnection` +""" +enum GroupSortByField { + """ + Group ID + """ + _id + + """ + Date and time at which this group was created + """ + createdAt + + """ + Group name + """ + name + + """ + Date and time at which this group was last updated + """ + updatedAt +} + +""" +Information about an image +""" +type ImageInfo { + """ + A list of URLs for various size files of this image + """ + URLs: ImageSizes + + """ + ID + """ + _id: ID + + """ + Sort by priority ascending when displaying more than one image for a product in a user interface. + This is an integer with 1 being the first / highest priority image. + """ + priority: Int + + """ + The related product ID + """ + productId: ID + + """ + The related variant ID, if linked with a particular variant + """ + variantId: ID +} + +""" +A list of URLs for various sizes of an image +""" +type ImageSizes { + """ + Use this URL to get a large resolution file for this image + """ + large: String + + """ + Use this URL to get a medium resolution file for this image + """ + medium: String + + """ + Use this URL to get this image with its original resolution as uploaded. This may not be + the true original size if there is a hard cap on how big image files can be. + """ + original: String + + """ + Use this URL to get a small resolution file for this image + """ + small: String + + """ + Use this URL to get a thumbnail resolution file for this image + """ + thumbnail: String +} + +type ImpersonateReturn { + authorized: Boolean + tokens: Tokens + user: User +} + +input ImpersonationUserIdentityInput { + userId: String + username: String + email: String +} + +""" +Details about a CartItemInput that failed to be added to a cart due to a price mismatch +""" +type IncorrectPriceFailureDetails { + """ + The current price in the system for this product configuration in the requested currency + """ + currentPrice: Money! + + """ + The productConfiguration that was provided with the CartItemInput that caused this failure + """ + productConfiguration: ProductConfiguration! + + """ + The price that was provided with the CartItemInput that caused this failure + """ + providedPrice: Money! +} + +""" +Represents a single staff member invitation +""" +type Invitation implements Node { + """ + The invitation ID + """ + _id: ID! + + """ + The e-mail address the invitation was sent to + """ + email: String! + + """ + The groups this person was invited to + """ + groups: [Group]! + + """ + The shop this person was invited to. Optional because we can also invite merchants to create their own shops. + """ + shop: Shop + + """ + The admin who invited this person + """ + invitedBy: Account +} + +""" +Wraps a list of `Invitation`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type InvitationConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [InvitationEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Invitation] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is an `Invitation` object +""" +type InvitationEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The account + """ + node: Invitation +} + +""" +Input parameters for the inviteShopMember mutation +""" +input InviteShopMemberInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The email address of the person to invite + """ + email: String! + + """ + The permission group for this person's new account. DEPRECATED. Use `groupIds` field instead. + """ + groupId: ID + + """ + The permission groups for this person's new account + """ + groupIds: [ID] + + """ + The invitee's full name + """ + name: String! + + """ + The ID of the shop to which you want to invite this person + """ + shopId: ID! + + """ + Whether the newly invited user should get admin UI access to the shop upon sign-up + """ + shouldGetAdminUIAccess: Boolean +} + +""" +The response from the `inviteShopMember` mutation +""" +type InviteShopMemberPayload { + """ + The account that was successfully created or found and updated by inviting this shop member + """ + account: Account + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +An object with any fields +""" +scalar JSONObject + +type LoginResult { + sessionId: String + tokens: Tokens + user: User +} + +""" +Mass units +""" +enum MassUnit { + """ + Gram + """ + g + + """ + Kilogram + """ + kg + + """ + Pound + """ + lb + + """ + Ounce + """ + oz +} + +""" +A FileRecord for a media file +""" +type MediaRecord { + """ + MediaRecord ID + """ + _id: ID! + + """ + Custom metadata for the media record + """ + metadata: MediaRecordMetadata! + + """ + Core info about the original uploaded file + """ + original: MediaRecordInfo! +} + +""" +Core info about the original uploaded media file +""" +type MediaRecordInfo { + """ + File name + """ + name: String! + + """ + File size + """ + size: Int! + + """ + File type + """ + type: String! + + """ + Date and time at which the file was last updated + """ + updatedAt: DateTime! + + """ + Date and time at which the file was uploaded + """ + uploadedAt: DateTime! +} + +""" +Core info about the original uploaded media file +""" +input MediaRecordInfoInput { + """ + File name + """ + name: String! + + """ + File size + """ + size: Int! + + """ + ID of the file uploaded to temporary storage + """ + tempStoreId: String! + + """ + File type + """ + type: String! + + """ + Date and time at which the file was last updated + """ + updatedAt: DateTime! + + """ + Date and time at which the file was uploaded + """ + uploadedAt: DateTime! +} + +""" +A FileRecord for a media file +""" +input MediaRecordInput { + """ + Custom metadata for the media record + """ + metadata: MediaRecordMetadataInput! + + """ + Core info about the original uploaded file + """ + original: MediaRecordInfoInput! +} + +""" +Custom metadata for the media record +""" +type MediaRecordMetadata { + """ + True if the MediaRecord is archived. This typically means that the media will not show in a storefront but the image file data still exists. + """ + isArchived: Boolean! + + """ + ID of the account that uploaded the file + """ + ownerId: String + + """ + Priority among media files with similar metadata + """ + priority: Int + + """ + ID of the related product, if the media is for a product + """ + productId: String + + """ + ID of the shop that owns the media + """ + shopId: String! + + """ + A string that identifies where this media will be used, for filtering + """ + type: String + + """ + ID of the related product variant, if the media is for a product variant + """ + variantId: String +} + +""" +Custom metadata for the media record +""" +input MediaRecordMetadataInput { + """ + Priority among media files with similar metadata + """ + priority: Int + + """ + ID of the related product, if the media is for a product + """ + productId: ID + + """ + A string that identifies where this media will be used, for filtering + """ + type: String + + """ + ID of the related product variant, if the media is for a product variant + """ + variantId: ID +} + +""" +Input to add a surcharge message with language +""" +input MessagesByLanguageInput { + """ + The message for this language + """ + content: String! + + """ + The language code + """ + language: String! +} + +""" +User defined attributes +""" +type Metafield { + """ + Field description + """ + description: String + + """ + Field key + """ + key: String + + """ + Field namespace + """ + namespace: String + + """ + Field scope + """ + scope: String + + """ + Field value + """ + value: String + + """ + Field value type + """ + valueType: String +} + +""" +User defined attributes. You can include only `key` and use these like tags, or also include a `value`. +""" +input MetafieldInput { + """ + Field description + """ + description: String + + """ + Field key + """ + key: String! + + """ + Field namespace + """ + namespace: String + + """ + Field scope + """ + scope: String + + """ + Field value + """ + value: String + + """ + Field value type + """ + valueType: String +} + +""" +Details about a CartItemInput that failed to be added to a cart due to a quantity error +""" +type MinOrderQuantityFailureDetails { + """ + The minimum quantity that can be added to a cart + """ + minOrderQuantity: Int! + + """ + The productConfiguration that was provided with the CartItemInput that caused this failure + """ + productConfiguration: ProductConfiguration! + + """ + The quantity that was provided with the CartItemInput that caused this failure + """ + quantity: Int! +} + +""" +Represents some amount of a single currency +""" +type Money { + """ + The numeric amount + """ + amount: Float! + + """ + The currency, for interpreting the `amount` + """ + currency: Currency! + + """ + The display amount, with any currency symbols and decimal places already added + """ + displayAmount: String! +} + +""" +Represents input for some amount of a single currency +""" +input MoneyInput { + """ + The numeric amount + """ + amount: Float! + + """ + The currency code, for interpreting the `amount` + """ + currencyCode: String! +} + +""" +Input for the moveOrderItems mutation +""" +input MoveOrderItemsInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The ID of the order fulfillment group from which all the items are to be moved. + """ + fromFulfillmentGroupId: ID! + + """ + The list of item IDs to move. The full quantity must be moved. + """ + itemIds: [ID]! + + """ + ID of the order that has the items you want to move + """ + orderId: ID! + + """ + The ID of the order fulfillment group to which all the items are to be moved. + """ + toFulfillmentGroupId: ID! +} + +""" +Response payload for the moveOrderItems mutation +""" +type MoveOrderItemsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated order + """ + order: Order! +} + +type Mutation { + """ + A test mutation that returns whatever string you send it + """ + echo( + """ + Any string + """ + str: String + ): String + + """ + Archive a MediaRecord to hide it without deleting the backing file data + """ + archiveMediaRecord( + """ + Mutation input + """ + input: ArchiveMediaRecordInput! + ): ArchiveMediaRecordPayload! + + """ + Create the MediaRecord for file data after you upload it + """ + createMediaRecord( + """ + Mutation input + """ + input: CreateMediaRecordInput! + ): CreateMediaRecordPayload! + + """ + Delete a MediaRecord to delete both the record and the backing file data + """ + deleteMediaRecord( + """ + Mutation input + """ + input: DeleteMediaRecordInput! + ): DeleteMediaRecordPayload! + + """ + Update the priority metadata for a MediaRecord. Used for sorting product and variant media in the catalog. + """ + updateMediaRecordPriority( + """ + Mutation input + """ + input: UpdateMediaRecordPriorityInput! + ): UpdateMediaRecordPriorityPayload! + + """ + Create a new shop + """ + createShop( + """ + Mutation input + """ + input: CreateShopInput! + ): CreateShopPayload! + + """ + Given shop data, update the Shops collection with this data + """ + updateShop( + """ + Mutation input + """ + input: UpdateShopInput! + ): UpdateShopPayload! + + """ + Returns app settings that are not shop specific. Plugins extend the GlobalSettings type to support + whatever settings they need. + """ + updateGlobalSettings( + """ + Mutation input + """ + input: UpdateGlobalSettingsInput! + ): UpdateGlobalSettingsPayload! + + """ + Returns app settings for a specific shop. Plugins extend the ShopSettings type to support + whatever settings they need. + """ + updateShopSettings( + """ + Mutation input + """ + input: UpdateShopSettingsInput! + ): UpdateShopSettingsPayload! + + """ + Retry a failed or cancelled email job + """ + retryFailedEmail( + """ + Mutation input + """ + input: RetryFailedEmailInput! + ): RetryFailedEmailPayload! + + """ + Create an address validation rule + """ + createAddressValidationRule( + """ + Mutation input + """ + input: CreateAddressValidationRuleInput! + ): CreateAddressValidationRulePayload! + + """ + Delete an address validation rule + """ + deleteAddressValidationRule( + """ + Mutation input + """ + input: DeleteAddressValidationRuleInput! + ): DeleteAddressValidationRulePayload! + + """ + Update an address validation rule + """ + updateAddressValidationRule( + """ + Mutation input + """ + input: UpdateAddressValidationRuleInput! + ): UpdateAddressValidationRulePayload! + + """ + Use this mutation to verify the SMTP email settings + """ + verifySMTPEmailSettings( + """ + Mutation input + """ + input: VerifySMTPEmailSettingsInput! + ): VerifySMTPEmailSettingsInputPayload! + + """ + Updates an existing template + """ + updateTemplate( + """ + Mutation input + """ + input: UpdateTemplateInput! + ): UpdateTemplatePayload! + + """ + Add a new address to the `addressBook` field for an account + """ + addAccountAddressBookEntry( + """ + Mutation input + """ + input: AddAccountAddressBookEntryInput! + ): AddAccountAddressBookEntryPayload + + """ + Add an email address to an account + """ + addAccountEmailRecord( + """ + Mutation input + """ + input: AddAccountEmailRecordInput! + ): AddAccountEmailRecordPayload + + """ + Create an account based off a user + """ + createAccount( + """ + Mutation input + """ + input: CreateAccountInput! + ): CreateAccountPayload + + """ + Remove an address from the `addressBook` field for an account + """ + removeAccountAddressBookEntry( + """ + Mutation input + """ + input: RemoveAccountAddressBookEntryInput! + ): RemoveAccountAddressBookEntryPayload + + """ + Remove an email address from an account + """ + removeAccountEmailRecord( + """ + Mutation input + """ + input: RemoveAccountEmailRecordInput! + ): RemoveAccountEmailRecordPayload + + """ + Send a reset password email to an email address from an account + """ + sendResetAccountPasswordEmail( + """ + Mutation input + """ + input: SendResetAccountPasswordEmailInput! + ): SendResetAccountPasswordEmailPayload + + """ + Set default email address for an account + """ + setAccountDefaultEmail( + """ + Mutation input + """ + input: SetAccountDefaultEmailInput! + ): SetAccountDefaultEmailPayload + + """ + Remove an address that exists in the `addressBook` field for an account + """ + updateAccountAddressBookEntry( + """ + Mutation input + """ + input: UpdateAccountAddressBookEntryInput! + ): UpdateAccountAddressBookEntryPayload + + """ + Update account fields + """ + updateAccount( + """ + Mutation input + """ + input: UpdateAccountInput! + ): UpdateAccountPayload + + """ + Bulk-update groups for accounts + """ + updateGroupsForAccounts( + """ + Mutation input + """ + input: UpdateGroupsForAccountsInput! + ): UpdateGroupsForAccountsPayload + + """ + Grant admin UI access for shops to a specific users + """ + grantAdminUIAccess( + input: GrantOrRevokeAdminUIAccessInput! + ): GrantOrRevokeAdminUIAccessPayload! + + """ + Revoke admin UI access to shops for specific users + """ + revokeAdminUIAccess( + input: GrantOrRevokeAdminUIAccessInput! + ): GrantOrRevokeAdminUIAccessPayload! + + """ + Update admin UI access to shops for specific users + """ + updateAdminUIAccess( + input: UpdateAdminUIAccessInput! + ): UpdateAdminUIAccessPayload! + + """ + Add an account to a group + """ + addAccountToGroup( + """ + Mutation input + """ + input: AddAccountToGroupInput! + ): AddAccountToGroupPayload + + """ + Create a new account group. These are usually used for account permissions + """ + createAccountGroup( + """ + Mutation input + """ + input: CreateAccountGroupInput! + ): CreateAccountGroupPayload + + """ + Remove an account from a group + """ + removeAccountFromGroup( + """ + Mutation input + """ + input: RemoveAccountFromGroupInput! + ): RemoveAccountFromGroupPayload + + """ + Remove an existing account group + """ + removeAccountGroup( + """ + Mutation input + """ + input: RemoveAccountGroupInput! + ): RemoveAccountGroupPayload + + """ + Update an existing account group + """ + updateAccountGroup( + """ + Mutation input + """ + input: UpdateAccountGroupInput! + ): UpdateAccountGroupPayload + + """ + Given a person's email address and name, invite them to create an account for a certain shop, + and put them in the provided permission group + """ + inviteShopMember( + """ + Mutation input + """ + input: InviteShopMemberInput! + ): InviteShopMemberPayload + + """ + Archive products + """ + archiveProducts( + """ + Mutation input + """ + input: ArchiveProductsInput! + ): ArchiveProductsPayload! + + """ + Archive product variants + """ + archiveProductVariants( + """ + Mutation input + """ + input: ArchiveProductVariantsInput! + ): ArchiveProductVariantsPayload! + + """ + Update the isVisible property of an array of products + """ + updateProductsVisibility( + """ + Mutation input + """ + input: UpdateProductsVisibilityInput! + ): UpdateProductsVisibilityPayload! + + """ + Create a new product + """ + createProduct( + """ + Mutation input + """ + input: CreateProductInput! + ): CreateProductPayload! + + """ + Create a new product variant + """ + createProductVariant( + """ + Mutation input + """ + input: CreateProductVariantInput! + ): CreateProductVariantPayload! + + """ + Clone an existing product + """ + cloneProducts( + """ + Mutation input + """ + input: CloneProductsInput! + ): CloneProductsPayload! + + """ + Clone an existing product variant + """ + cloneProductVariants( + """ + Mutation input + """ + input: CloneProductVariantsInput! + ): CloneProductVariantsPayload! + + """ + Update an existing product + """ + updateProduct( + """ + Mutation input + """ + input: UpdateProductInput! + ): UpdateProductPayload! + + """ + Update an existing product variant + """ + updateProductVariant( + """ + Mutation input + """ + input: UpdateProductVariantInput! + ): UpdateProductVariantPayload! + + """ + Bulk operation for adding an array of tags to an array of products + """ + addTagsToProducts( + """ + input which must includes an array of product ids and an array of tag ids + """ + input: ProductTagsOperationInput! + ): ProductTagsOperationPayload! + + """ + Bulk operation for removing an array of tags from an array of products + """ + removeTagsFromProducts( + """ + input which must includes an array of product ids and an array of tag ids + """ + input: ProductTagsOperationInput! + ): ProductTagsOperationPayload! + + """ + Publish products to the Catalog collection by product ID + """ + publishProductsToCatalog( + """ + Array of Product ID + """ + productIds: [ID]! + ): [CatalogItemProduct] + + """ + Adds a new tag + """ + addTag( + """ + Mutation input + """ + input: AddTagInput! + ): AddTagPayload! + + """ + Removes an existing tag + """ + removeTag( + """ + Mutation input + """ + input: RemoveTagInput! + ): RemoveTagPayload! + + """ + Add an image to the tag + """ + setTagHeroMedia( + """ + Mutation input + """ + input: SetTagHeroMediaInput! + ): SetTagHeroMediaPayload! + + """ + Updates an existing tag + """ + updateTag( + """ + Mutation input + """ + input: UpdateTagInput! + ): UpdateTagPayload! + + """ + Update an existing product variants prices + """ + updateProductVariantPrices( + """ + Mutation input + """ + input: UpdateProductVariantPricesInput! + ): UpdateProductVariantPricesPayload! + + """ + Force recalculation of the system-managed `inventoryReserved` field based on current order statuses + """ + recalculateReservedSimpleInventory( + """ + Mutation input + """ + input: RecalculateReservedSimpleInventoryInput! + ): RecalculateReservedSimpleInventoryPayload! + + """ + Update the SimpleInventory info for a product configuration + """ + updateSimpleInventory( + """ + Mutation input + """ + input: UpdateSimpleInventoryInput! + ): UpdateSimpleInventoryPayload! + + """ + Add item(s) to a cart + """ + addCartItems( + """ + Mutation input + """ + input: AddCartItemsInput! + ): AddCartItemsPayload! + + """ + Create a new cart + """ + createCart( + """ + Mutation input + """ + input: CreateCartInput! + ): CreateCartPayload! + + """ + Reconcile an anonymous cart with the current account cart for the same shop + """ + reconcileCarts( + """ + Mutation input + """ + input: ReconcileCartsInput! + ): ReconcileCartsPayload! + + """ + Remove item(s) from a cart + """ + removeCartItems( + """ + Mutation input + """ + input: RemoveCartItemsInput! + ): RemoveCartItemsPayload! + + """ + Set the email address for an anonymous cart + """ + setEmailOnAnonymousCart( + """ + Mutation input + """ + input: SetEmailOnAnonymousCartInput! + ): SetEmailOnAnonymousCartPayload! + + """ + Update cart item(s) quantity. Use absolute quantity. If updating to 0, the item will be removed. + """ + updateCartItemsQuantity( + """ + Mutation input + """ + input: UpdateCartItemsQuantityInput! + ): UpdateCartItemsQuantityPayload! + + """ + Select a fulfillment option from the `availableFulfillmentOptions` list for a fulfillment group + """ + selectFulfillmentOptionForGroup( + """ + Mutation input + """ + input: SelectFulfillmentOptionForGroupInput! + ): SelectFulfillmentOptionForGroupPayload! + + """ + Set the shipping address for all fulfillment groups + """ + setShippingAddressOnCart( + """ + Mutation input + """ + input: SetShippingAddressOnCartInput! + ): SetShippingAddressOnCartPayload! + + """ + Clients should call this as necessary during checkout to update the `availableFulfillmentOptions` + property for all fulfillment groups of the cart with fresh price quotes. These need to be + recalculated every time the items in that group change. When the order is placed, the chosen + option for each group will have its prices recalculated one last time. If the prices do not match, + order creation will fail. + """ + updateFulfillmentOptionsForGroup( + """ + Mutation input + """ + input: UpdateFulfillmentOptionsForGroupInput! + ): UpdateFulfillmentOptionsForGroupPayload! + + """ + Use this mutation to add a new order fulfillment group to an order. It must have at least one + item. Items may be provided or moved from another existing group or both. + """ + addOrderFulfillmentGroup( + """ + Mutation input + """ + input: AddOrderFulfillmentGroupInput! + ): AddOrderFulfillmentGroupPayload! + + """ + Use this mutation to cancel one item of an order, either for the full ordered quantity + or for a partial quantity. If partial, the item will be split into two items and the + original item will have a lower quantity and will be canceled. + + If this results in all items in a fulfillment group being canceled, the group will also + be canceled. If this results in all fulfillment groups being canceled, the full order will + also be canceled. + """ + cancelOrderItem( + """ + Mutation input + """ + input: CancelOrderItemInput! + ): CancelOrderItemPayload! + + """ + Use this mutation to create a refund on a payment method used to make the order + """ + createRefund( + """ + Mutation input + """ + input: CreateRefundInput! + ): CreateRefundPayload! + + """ + Use this mutation to move one or more items between existing order fulfillment groups. + """ + moveOrderItems( + """ + Mutation input + """ + input: MoveOrderItemsInput! + ): MoveOrderItemsPayload! + + """ + Use this mutation to place an order, providing information necessary to pay for it. + The order will be placed only if authorization is successful for all submitted payments. + """ + placeOrder( + """ + Mutation input + """ + input: PlaceOrderInput! + ): PlaceOrderPayload! + + """ + Use this mutation to reduce the quantity of one item of an order and create + a new item for the remaining quantity in the same fulfillment group, and with the + same item status. You may want to do this if you are only able to partially fulfill + the item order right now. + """ + splitOrderItem( + """ + Mutation input + """ + input: SplitOrderItemInput! + ): SplitOrderItemPayload! + + """ + Use this mutation to update order details after the order has been placed. + """ + updateOrder( + """ + Mutation input + """ + input: UpdateOrderInput! + ): UpdateOrderPayload! + + """ + Use this mutation to update an order fulfillment group status and tracking information. + """ + updateOrderFulfillmentGroup( + """ + Mutation input + """ + input: UpdateOrderFulfillmentGroupInput! + ): UpdateOrderFulfillmentGroupPayload! + + """ + Approve one or more payments for an order + """ + approveOrderPayments( + """ + Mutation input + """ + input: ApproveOrderPaymentsInput! + ): ApproveOrderPaymentsPayload! + + """ + Capture one or more payments for an order + """ + captureOrderPayments( + """ + Mutation input + """ + input: CaptureOrderPaymentsInput! + ): CaptureOrderPaymentsPayload! + + """ + Enable a payment method for a shop + """ + enablePaymentMethodForShop( + """ + Mutation input + """ + input: EnablePaymentMethodForShopInput! + ): EnablePaymentMethodForShopPayload! + + """ + Create a new discount code + """ + createDiscountCode( + """ + Mutation input + """ + input: CreateDiscountCodeInput! + ): CreateDiscountCodePayload + + """ + Update a discount code + """ + updateDiscountCode( + """ + Mutation input + """ + input: UpdateDiscountCodeInput! + ): UpdateDiscountCodePayload + + """ + Delete a discount code + """ + deleteDiscountCode( + """ + Mutation input + """ + input: DeleteDiscountCodeInput! + ): DeleteDiscountCodePayload + + """ + Apply a discount code to a cart + """ + applyDiscountCodeToCart( + """ + Mutation input + """ + input: ApplyDiscountCodeToCartInput! + ): ApplyDiscountCodeToCartPayload! + + """ + Remove a discount code from a cart + """ + removeDiscountCodeFromCart( + """ + Mutation input + """ + input: RemoveDiscountCodeFromCartInput! + ): RemoveDiscountCodeFromCartPayload! + + """ + Create a surcharge + """ + createSurcharge( + """ + Mutation input + """ + input: CreateSurchargeInput! + ): CreateSurchargePayload! + + """ + Delete a flat rate fulfillment restriction + """ + deleteSurcharge( + """ + Mutation input + """ + input: DeleteSurchargeInput! + ): DeleteSurchargePayload! + + """ + Update a flat rate fulfillment surcharge + """ + updateSurcharge( + """ + Mutation input + """ + input: UpdateSurchargeInput! + ): UpdateSurchargePayload! + + """ + Create a flat rate fulfillment method + """ + createFlatRateFulfillmentMethod( + """ + Mutation input + """ + input: CreateFlatRateFulfillmentMethodInput! + ): CreateFlatRateFulfillmentMethodPayload! + + """ + Update a flat rate fulfillment method + """ + updateFlatRateFulfillmentMethod( + """ + Mutation input + """ + input: UpdateFlatRateFulfillmentMethodInput! + ): UpdateFlatRateFulfillmentMethodPayload! + + """ + Delete a flat rate fulfillment method + """ + deleteFlatRateFulfillmentMethod( + """ + Mutation input + """ + input: DeleteFlatRateFulfillmentMethodInput! + ): DeleteFlatRateFulfillmentMethodPayload! + + """ + Create a flat rate fulfillment method restriction. + """ + createFlatRateFulfillmentRestriction( + """ + Mutation input + """ + input: CreateFlatRateFulfillmentRestrictionInput! + ): CreateFlatRateFulfillmentRestrictionPayload! + + """ + Delete a flat rate fulfillment method restriction + """ + deleteFlatRateFulfillmentRestriction( + """ + Mutation input + """ + input: DeleteFlatRateFulfillmentRestrictionInput! + ): DeleteFlatRateFulfillmentRestrictionPayload! + + """ + Update a flat rate fulfillment method restriction + """ + updateFlatRateFulfillmentRestriction( + """ + Mutation input + """ + input: UpdateFlatRateFulfillmentRestrictionInput! + ): UpdateFlatRateFulfillmentRestrictionPayload! + + """ + Create a new tax rate + """ + createTaxRate( + """ + Mutation input + """ + input: CreateTaxRateInput! + ): CreateTaxRatePayload + + """ + Update a tax rate + """ + updateTaxRate( + """ + Mutation input + """ + input: UpdateTaxRateInput! + ): UpdateTaxRatePayload + + """ + Delete a tax rate + """ + deleteTaxRate( + """ + Mutation input + """ + input: DeleteTaxRateInput! + ): DeleteTaxRatePayload + + """ + Create a new navigation item + """ + createNavigationItem( + """ + Mutation input + """ + input: CreateNavigationItemInput! + ): CreateNavigationItemPayload + + """ + Create a new navigation tree + """ + createNavigationTree( + """ + Mutation input + """ + input: CreateNavigationTreeInput! + ): CreateNavigationTreePayload! + + """ + Delete a navigation item + """ + deleteNavigationItem( + """ + Mutation input + """ + input: DeleteNavigationItemInput! + ): DeleteNavigationItemPayload + + """ + Publish the draft structure for a navigation tree and the draft changes for all of its navigation items. Sets hasUnpublishedChanges to false on tree and its items + """ + publishNavigationChanges( + """ + Mutation input + """ + input: PublishNavigationChangesInput! + ): PublishNavigationChangesPayload + + """ + Update an existing navigation item's draft data. Sets hasUnpublishedChanges to true + """ + updateNavigationItem( + """ + Mutation input + """ + input: UpdateNavigationItemInput! + ): UpdateNavigationItemPayload + + """ + Update an existing navigation tree's draft items. Sets hasUnpublishedChanges to true + """ + updateNavigationTree( + """ + Mutation input + """ + input: UpdateNavigationTreeInput! + ): UpdateNavigationTreePayload + + """ + Generate sitemap documents + """ + generateSitemaps( + """ + Mutation input + """ + input: GenerateSitemapsInput + ): GenerateSitemapsPayload! + createUser(user: CreateUserInput!): CreateUserResult + verifyEmail(token: String!): Boolean + resetPassword(token: String!, newPassword: String!): LoginResult + sendVerificationEmail(email: String!): Boolean + sendResetPasswordEmail(email: String!): Boolean + addEmail(newEmail: String!): Boolean + changePassword(oldPassword: String!, newPassword: String!): Boolean + twoFactorSet(secret: TwoFactorSecretKeyInput!, code: String!): Boolean + twoFactorUnset(code: String!): Boolean + impersonate( + accessToken: String! + impersonated: ImpersonationUserIdentityInput! + ): ImpersonateReturn + refreshTokens(accessToken: String!, refreshToken: String!): LoginResult + logout: Boolean + authenticate( + serviceName: String! + params: AuthenticateParamsInput! + ): LoginResult + verifyAuthentication( + serviceName: String! + params: AuthenticateParamsInput! + ): Boolean +} + +""" +Represents a single navigation item +""" +type NavigationItem implements Node { + """ + The navigation item ID + """ + _id: ID! + + """ + The date and time at which this navigation item was created + """ + createdAt: DateTime! + + """ + The published data for this navigation item + """ + data: NavigationItemData + + """ + The draft/unpublished data for this navigation item + """ + draftData: NavigationItemData + + """ + Whether the navigation item has unpublished changes + """ + hasUnpublishedChanges: Boolean + + """ + An object storing additional metadata about the navigation item (such as its related tag) + """ + metadata: JSONObject + + """ + The ID of the shop the navigation item belongs to + """ + shopId: ID! +} + +""" +Wraps a list of `NavigationItem`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type NavigationItemConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [NavigationItemEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [NavigationItem] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +Represents the translated content for a navigation item +""" +type NavigationItemContent { + """ + The language of the piece of navigation content + """ + language: String! + + """ + The translated value, in plain text or markdown + """ + value: String +} + +""" +NavigationItem content input +""" +input NavigationItemContentInput { + """ + The language of the piece of navigation content + """ + language: String! + + """ + The translated value, in plain text or markdown + """ + value: String +} + +""" +Represents the data for a navigation item +""" +type NavigationItemData { + """ + CSS class names to add to the menu item for display + """ + classNames: String + + """ + The content for the navigation item, in one or more languages + """ + content: [NavigationItemContent] + + """ + The translated content for a navigation item + """ + contentForLanguage: String + + """ + Whether the provided URL is relative or external + """ + isUrlRelative: Boolean + + """ + Whether the navigation item should trigger a new tab/window to open when clicked + """ + shouldOpenInNewWindow: Boolean + + """ + The URL for the navigation item to link to + """ + url: String +} + +""" +NavigationItemData input +""" +input NavigationItemDataInput { + """ + CSS class names to add to the menu item for display + """ + classNames: String + + """ + The content for the navigation item, in one or more languages + """ + content: [NavigationItemContentInput] + + """ + Whether the provided URL is relative or external + """ + isUrlRelative: Boolean + + """ + Whether the navigation item should trigger a new tab/window to open when clicked + """ + shouldOpenInNewWindow: Boolean + + """ + The URL for the navigation item to link to + """ + url: String +} + +""" +A connection edge in which each node is a `NavigationItem` object +""" +type NavigationItemEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The navigation item + """ + node: NavigationItem +} + +""" +NavigationItem input +""" +input NavigationItemInput { + """ + The draft/unpublished data for this navigation item + """ + draftData: NavigationItemDataInput + + """ + An object storing additional metadata about the navigation item (such as its related tag) + """ + metadata: JSONObject + + """ + Shop ID of the navigation item + """ + shopId: ID! +} + +""" +The fields by which you are allowed to sort any query that returns a `NavigationItemConnection` +""" +enum NavigationItemSortByField { + """ + Sort by NavigationItem ID + """ + _id + + """ + Sort by when the NavigationItem was created + """ + createdAt +} + +""" +Represents a navigation tree containing multiple levels of navigation items +""" +type NavigationTree implements Node { + """ + The navigation tree ID + """ + _id: ID! + + """ + The draft navigation items that make up this tree + """ + draftItems: [NavigationTreeItem] + + """ + Whether the navigation item has unpublished changes + """ + hasUnpublishedChanges: Boolean + + """ + The published navigation items that make up this tree + """ + items: [NavigationTreeItem] + + """ + The name of the tree, for operator display purposes. Assumed to be in the primary shop's language + """ + name: String! + + """ + The ID of the shop this navigation tree belongs to + """ + shopId: ID! +} + +""" +NavigationTree input +""" +input NavigationTreeInput { + """ + The draft navigation items that make up this tree + """ + draftItems: [NavigationTreeItemInput] + + """ + The name of the tree, for operator display purposes + """ + name: String +} + +""" +Represents a navigation item and its children in a tree +""" +type NavigationTreeItem { + """ + Whether the navigation item should display its children + """ + expanded: Boolean + + """ + Whether the navigation item should be hidden from customers + """ + isPrivate: Boolean + + """ + Whether the navigaton item is a secondary navigation item + """ + isSecondary: Boolean + + """ + Whether the navigation ttem should shown in query results for customers and admins + """ + isVisible: Boolean + + """ + The child navigation items + """ + items: [NavigationTreeItem] + + """ + The navigation item + """ + navigationItem: NavigationItem! +} + +""" +NavigationTree item input +""" +input NavigationTreeItemInput { + """ + Whether the navigation item should display its children + """ + expanded: Boolean + + """ + Whether the navigation item should be hidden from customers + """ + isPrivate: Boolean + + """ + Whether the navigaton item is a secondary navigation item + """ + isSecondary: Boolean + + """ + Whether the navigation ttem should shown in query results for customers and admins + """ + isVisible: Boolean + + """ + The child navigation items + """ + items: [NavigationTreeItemInput] + + """ + The ID of the navigation item + """ + navigationItemId: ID! +} + +""" +Objects implementing the Node interface will always have an _id field that is globally unique. +""" +interface Node { + """ + The ID of the object + """ + _id: ID! +} + +""" +Objects implementing the NodeEdge interface will always have a node and a cursor +that represents that node for purposes of requesting paginated results. +""" +interface NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The node itself + """ + node: Node +} + +""" +An order +""" +type Order implements Node { + """ + The Order ID + """ + _id: ID! + + """ + The account that placed the order. Some orders are created for anonymous users. Anonymous orders have a null account. + """ + account: Account + + """ + The ID of the cart that created this order. Carts are deleted after becoming orders, so this is just a reference. + """ + cartId: ID + + """ + The date and time at which the cart was created, which is when the first item was added to it. + """ + createdAt: DateTime! + + """ + The order status for display in UI + """ + displayStatus( + """ + The language in which you want the status. If no translation is available for this language, + it will be in the default language of the shop that owns the order. + """ + language: String! + ): String! + + """ + An email address that has been associated with the cart + """ + email: String + + """ + One or more fulfillment groups. Each of these are fulfilled and charged as separate orders. + """ + fulfillmentGroups: [OrderFulfillmentGroup]! + + """ + Notes about the order. This will always return an array but it may be empty + """ + notes: [OrderNote]! + + """ + Payments that collectively have paid or will pay for the total amount due for this order. + May be null if no payment is needed. + """ + payments: [Payment] + + """ + An ID by which the customer can reference this order when enquiring about it. A storefront user + interface may show this to customers. Do not display other IDs (`_id`) to customers. + """ + referenceId: String! + + """ + Refunds that have been applied to the payments on this order. + """ + refunds: [Refund] + + """ + The shop through which the order was placed + """ + shop: Shop! + + """ + The machine-readable order status. + """ + status: String! + + """ + A summary of the totals for all fulfillment groups for this order + """ + summary: OrderSummary! + + """ + Total quantity of all items in the order + """ + totalItemQuantity: Int! + + """ + The date and time at which this order was last updated + """ + updatedAt: DateTime! + + """ + Surcharges applied to this order + """ + surcharges: [AppliedSurcharge]! +} + +""" +Wraps a list of `Order`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type OrderConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [OrderEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Order] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `Order` object +""" +type OrderEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The order + """ + node: Order +} + +""" +Input type for filters to by applied to an Orders list +""" +input OrderFilterInput { + """ + A createdAt date range to filter by + """ + createdAt: CreatedAtInput + + """ + An order's fulfillment status + """ + fulfillmentStatus: [OrderFulfillmentStatus] + + """ + An order's payment status + """ + paymentStatus: [OrderPaymentStatus] + + """ + Keywords typed by the user in the search input field + """ + searchField: String + + """ + The order's status to filter by + """ + status: OrderStatus +} + +""" +An order fulfillment group +""" +type OrderFulfillmentGroup implements Node { + """ + The order fulfillment group ID + """ + _id: ID! + + """ + Information needed by the selected fulfillment method to properly fulfill the order + """ + data: OrderFulfillmentGroupData + + """ + The order status for display in UI + """ + displayStatus( + """ + The language in which you want the status. If no translation is available for this language, + it will be in the default language of the shop that owns the order. + """ + language: String! + ): String! + + """ + The items that are part of this fulfillment group + """ + items( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + By default, order items are sorted by when they were added to the order, newest first. Set this to sort by one of the other allowed fields + """ + sortBy: OrderFulfillmentGroupItemsSortByField = addedAt + ): OrderItemConnection + + """ + The fulfillment method that was selected, with its price quote + """ + selectedFulfillmentOption: FulfillmentOption! + + """ + The shipping label URL + """ + shippingLabelUrl: String + + """ + The shop responsible for fulfilling this order + """ + shop: Shop! + + """ + The machine-readable fulfillment group status. + """ + status: String! + + """ + A summary of the totals for this group + """ + summary: OrderSummary! + + """ + Total quantity of all items in the group + """ + totalItemQuantity: Int! + + """ + The order fulfillment group shipment tracking number + """ + tracking: String + + """ + The order fulfillment group shipment tracking URL + """ + trackingUrl: String + + """ + The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital` + """ + type: FulfillmentType! + + """ + A summary of calculated taxes for this group. + """ + taxSummary: TaxSummary +} + +""" +Extra data for an order fulfillment group +""" +union OrderFulfillmentGroupData = ShippingOrderFulfillmentGroupData + +""" +Information needed by the selected fulfillment method to properly fulfill the order +""" +input OrderFulfillmentGroupDataInput { + """ + The mailing address to which this fulfillment group should be shipped + """ + shippingAddress: AddressInput +} + +""" +Similar to `OrderFulfillmentGroupInput` but `items` can be omitted if moving existing items to the new group +""" +input OrderFulfillmentGroupExistingOrderInput { + """ + Information needed by the selected fulfillment method to properly fulfill the order + """ + data: OrderFulfillmentGroupDataInput + + """ + The list of items to be ordered + """ + items: [OrderFulfillmentGroupItemInput] + + """ + The ID of the fulfillment method to be used for this order group + """ + selectedFulfillmentMethodId: ID! + + """ + The shop that owns these items and needs to fulfill this part of the order + """ + shopId: ID! + + """ + The total price of the items, fulfillment, and taxes, for this group, less any discounts, in the + `order.currencyCode` currency. This value is not trusted; the actual total is calculated by the + Order service. However, providing this value prevents an order being created for an amount that + does not match what was shown to the shopper in order preview. + """ + totalPrice: Float + + """ + The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital` + """ + type: FulfillmentType! +} + +""" +Input for an `OrderFulfillmentGroup` +""" +input OrderFulfillmentGroupInput { + """ + Information needed by the selected fulfillment method to properly fulfill the order + """ + data: OrderFulfillmentGroupDataInput + + """ + The list of items to be ordered + """ + items: [OrderFulfillmentGroupItemInput]! + + """ + The ID of the fulfillment method to be used for this order group + """ + selectedFulfillmentMethodId: ID! + + """ + The shop that owns these items and needs to fulfill this part of the order + """ + shopId: ID! + + """ + The total price of the items, fulfillment, and taxes, for this group, less any discounts, in the + `order.currencyCode` currency. This value is not trusted; the actual total is calculated by the + Order service. However, providing this value prevents an order being created for an amount that + does not match what was shown to the shopper in order preview. + """ + totalPrice: Float + + """ + The fulfillment type. Any valid type that has been registered by a fulfillment plugin. Examples: `shipping`, `digital` + """ + type: FulfillmentType! +} + +""" +Input for an `OrderFulfillmentGroupItem` +""" +input OrderFulfillmentGroupItemInput { + """ + The date and time at which this item was first added to the source cart, if this is something you want to track + """ + addedAt: DateTime + + """ + The price of the item, in the `order.currencyCode` currency. This value is not trusted; the actual price + is confirmed by the Order service. However, providing this value prevents an order being created for an + amount that does not match what was shown to the shopper in order preview. + """ + price: Float! + + """ + The product and chosen options + """ + productConfiguration: ProductConfigurationInput! + + """ + The desired quantity of this item. This must be a positive integer. + """ + quantity: Int! +} + +""" +Allowed values for the `OrderFulfillmentGroupItems` sortBy parameter +""" +enum OrderFulfillmentGroupItemsSortByField { + """ + Sort by the item ID + """ + _id + + """ + Sort by the date and time when the item was added to the order + """ + addedAt +} + +""" +Available order fulfillment statuses +""" +enum OrderFulfillmentStatus { + """ + An order that has been completed + """ + completed + + """ + Newly created order that needs processing + """ + new + + """ + An order that is currently being processed + """ + processing +} + +""" +Input for placing an order +""" +input OrderInput { + """ + The ID of the cart that is becoming an order. This is optional, and you can create an order without ever + creating a cart. If you do have a cart, there are two good reasons to provide this. First, it serves as a + reference. Second, it allows the Cart service to automatically delete the related cart after the order is + created. + """ + cartId: String + + """ + The code for the currency in which all values are being provided + """ + currencyCode: String! + + """ + An email address to use for order tracking and correspondence. If a logged in user is placing an order, + we recommend that you use their "orders" email address, if they have one, or their default email address. + Or you can ask them to provide any email address. + """ + email: String! + + """ + One or more fulfillment groups for the order. These are the actual orders that need to be fulfilled, + separate by shop, fulfillment type, and shipping origin or destination. + """ + fulfillmentGroups: [OrderFulfillmentGroupInput]! + + """ + The shop through which the order should be placed. Payment settings from this shop will be used. Note that + each fulfillment group also has a shop ID, which represents the shop that needs to fulfill that part of the + order, and those shop IDs may or may not match this one. + """ + shopId: String! +} + +""" +A single item in an order. The item contains information about a purchase. +""" +type OrderItem implements Node { + """ + The order item ID + """ + _id: ID! + + """ + " + The date and time at which this item was first added to the associated cart. + If an item is added, removed, and then added again, this will reflect the most recent addition. + However, if an item is added twice, the quantity will increase but this date will remain + the initial added date. + """ + addedAt: DateTime + + """ + FUTURE. Additional attributes of the chosen item. For example, if this item is for a product, socks, where `blue` and `small` + options were chosen for some configurable attributes, then `color:blue` and `size:small` will be indicated here. + """ + attributes: [OrderItemAttribute] + + """ + If this order item is canceled, the reason for cancelation, if provided + """ + cancelReason: String + + """ + The date and time at which the order item was created + """ + createdAt: DateTime! + + """ + The URLs for a picture of the item in various sizes + """ + imageURLs: ImageSizes + + """ + Arbitrary additional metadata about this cart item. + """ + metafields: [Metafield] + + """ + The short title of the associated option, if this is an option item + """ + optionTitle: String + + """ + Packing information such as item weight, height, length, and depth. Used for calculating shipping rates. + """ + parcel: ShippingParcel + + """ + The price of the item at the time of purchase + """ + price: Money! + + """ + The product and chosen options + """ + productConfiguration: ProductConfiguration! + + """ + The product's slug + """ + productSlug: String + + """ + The list of tags that have been applied to this product + """ + productTags( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, tags are sorted by ID. Set this to sort by one of the other allowed fields + """ + sortBy: TagSortByField = _id + ): TagConnection + + """ + The type of product, used to display cart items differently + """ + productType: String + + """ + The product vendor + """ + productVendor: String + + """ + The quantity of this item that has been added to the cart. This must be a positive integer. Remove this `CartItem` from it's associated cart if you want `0` of this item. + """ + quantity: Int! + + """ + The shop associated with this cart item. + """ + shop: Shop! + + """ + The machine-readable order item status. + """ + status: String! + + """ + The price of the item multiplied by the quantity of this item ordered + """ + subtotal: Money! + + """ + A title for use in orders that conveys the selected product's title + chosen options + """ + title: String! + + """ + The date and time at which this item was last updated + """ + updatedAt: DateTime! + + """ + The selected variant title + """ + variantTitle: String + + """ + Is this a taxable item? + """ + isTaxable: Boolean! + + """ + Total tax calculated for this item + """ + tax: Money! + + """ + The tax code for this item + """ + taxCode: String + + """ + Amount of subtotal that is taxable + """ + taxableAmount: Money! + + """ + List of calculated taxes due for this item + """ + taxes: [CalculatedTax]! +} + +""" +One attribute of an order item +""" +type OrderItemAttribute { + """ + The attribute label, e.g., Color + """ + label: String + + """ + The attribute value, e.g., Blue + """ + value: String +} + +""" +Wraps a list of `OrderItem`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type OrderItemConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [OrderItemEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [OrderItem] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `OrderItem` object +""" +type OrderItemEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The order item + """ + node: OrderItem +} + +""" +A note about an order +""" +type OrderNote { + """ + The account who wrote this note + """ + account: Account! + + """ + The content of the note + """ + content: String! + + """ + The date and time at which this note was created + """ + createdAt: DateTime! + + """ + The date and time at which this note was last updated + """ + updatedAt: DateTime! +} + +""" +Order payment status +""" +enum OrderPaymentStatus { + """ + Payments that have been successfully processed + """ + completed + + """ + A payment intent has been created + """ + created +} + +""" +Order status +""" +enum OrderStatus { + """ + Canceled order + """ + canceled + + """ + A completed order + """ + completed + + """ + A new order that needs processing + """ + new + + """ + An order that is being processed + """ + processing +} + +""" +A summary of the totals for this order +""" +type OrderSummary { + """ + The total of all discounts applied, as a positive number + """ + discountTotal: Money! + + """ + The calculated tax-exclusive tax rate on all items and fulfillment prices (taxTotal / taxableAmount) + """ + effectiveTaxRate: Rate! + + """ + The total price of all chosen fulfillment methods + """ + fulfillmentTotal: Money! + + """ + The combined prices of all cart items + """ + itemTotal: Money! + + """ + The total estimated tax that has not already been included in the item prices + """ + taxTotal: Money! + + """ + The total amount that was deemed taxable by the tax service + """ + taxableAmount: Money! + + """ + The sum of `itemTotal`, `fulfillmentTotal`, and `taxTotal`, minus `discountTotal` + """ + total: Money! + + """ + The total of all suurcharges applied + """ + surchargeTotal: Money +} + +""" +Wraps a list of `Order`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type OrdersByAccountIdConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [OrdersByAccountIdEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Order] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `Order` object +""" +type OrdersByAccountIdEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The order + """ + node: Order +} + +""" +The fields by which you are allowed to sort any query that returns a `OrdersByAccountIdConnection` +""" +enum OrdersByAccountIdSortByField { + """ + Sort by the order ID + """ + _id + + """ + Sort by the date and time when the order was placed + """ + createdAt +} + +""" +The fields by which you are allowed to sort any query that returns a `OrderConnection` +""" +enum OrdersSortByField { + """ + Sort by the order ID + """ + _id + + """ + Sort by the date and time when the order was placed + """ + createdAt +} + +""" +Pagination information. When requesting pages of results, you can use endCursor or startCursor +as your before or after parameters for the query you are paging. +""" +type PageInfo { + """ + When paginating forwards, the cursor to continue. + """ + endCursor: ConnectionCursor + + """ + When paginating forwards, are there more items? + """ + hasNextPage: Boolean! + + """ + When paginating backwards, are there more items? + """ + hasPreviousPage: Boolean! + + """ + When paginating backwards, the cursor to continue. + """ + startCursor: ConnectionCursor +} + +""" +Information about a payment made +""" +type Payment implements Node { + """ + The Payment ID + """ + _id: ID! + + """ + The amount that will be applied to this payment method. If there are multiple payment methods applied to the + cart, this may be less than the cart total. + """ + amount: Money! + + """ + The billing address for this payment, if one was collected + """ + billingAddress: Address + + """ + If status is `error` due to a capture error, this code describes the error in a machine-readable way. + """ + captureErrorCode: String + + """ + If status is `error` due to a capture error, this code describes the error in a human-readable way. + """ + captureErrorMessage: String + + """ + For card payments, the brand of the card. Useful for showing card icons for common brands. + """ + cardBrand: String + + """ + The date and time at which this payment was created + """ + createdAt: DateTime! + + """ + The shopper-provided data needed to complete the payment using this method. + For example, a billing address, store credit code, stored credit card ID, etc. + """ + data: PaymentData + + """ + Use this identifier when showing this payment in a user interface + """ + displayName: String! + + """ + Has the payment authorization been canceled? + """ + isAuthorizationCanceled: Boolean! + + """ + Has the payment been captured? If false, it is just an authorization. + """ + isCaptured: Boolean! + + """ + The payment method + """ + method: PaymentMethod! + + """ + The payment mode + """ + mode: String + + """ + The payment processor + """ + processor: String + + """ + Refunds that have been applied to this payment. + """ + refunds: [Refund] + + """ + Risk level of payment + """ + riskLevel: RiskLevel + + """ + The current status of this payment + """ + status: PaymentStatus! + + """ + The payment transaction ID + """ + transactionId: String +} + +""" +Data identifying a payment for an order +""" +union PaymentData = FakeData | StripeCardPaymentData | ExampleIOUPaymentData + +""" +Input for adding order payments +""" +input PaymentInput { + """ + Amount to charge, which must be less than or equal to the order total. This is assumed + to be in the same currency as the order. Set to `null` to charge the remaining amount + to this payment method, which might be the full order total if this is the only payment. + """ + amount: Float! + + """ + The billing address entered by the shopper. If omitted, the billing address on the order input + will be used. Some payment methods may not require a billing address but others will fail + authorization without one, so be sure that client UI code is aware of which payment methods + require collecting one. + """ + billingAddress: AddressInput + + """ + Any additional user-provided input necessary to authorize and capture the payment + """ + data: JSONObject + + """ + The name of the payment method to use for this payment + """ + method: PaymentMethodName! +} + +""" +Describes a payment method +""" +type PaymentMethod { + """ + If this is `false`, the payment method does not support refunding. Use this to hide refund UI. + """ + canRefund: Boolean! + + """ + Data for this method. The data format differs for each method + """ + data: PaymentMethodData + + """ + Human-readable display name + """ + displayName: String! + + """ + Whether the payment method is enabled on a given shop + """ + isEnabled: Boolean! + + """ + The payment method name. Any valid name that has been registered by a payment plugin. e.g., saved_card + """ + name: String! + + """ + Name of the plugin that added the payment method + """ + pluginName: String! +} + +""" +Any extra data needed by the payment method +""" +union PaymentMethodData = FakeData | ExampleIOUPaymentMethodData + +""" +The name of a payment method, which is how payment methods are keyed +""" +enum PaymentMethodName { + """ + No payment method + """ + none + + """ + Stripe Card payment method + """ + stripe_card + + """ + IOU Example payment method + """ + iou_example +} + +""" +Valid payment statuses +""" +enum PaymentStatus { + """ + A shop operator adjusted the payment amount after the order was placed + """ + adjustments + + """ + A shop operator has approved this payment + """ + approved + + """ + A shop operator has canceled this payment before it was captured + """ + canceled + + """ + A shop operator has captured this payment + """ + completed + + """ + Upon placing an order, the status of all payments for that order begins at 'created' + """ + created + + """ + There was an error capturing the payment + """ + error + + """ + A shop operator has refunded some but not all of this payment + """ + partialRefund + + """ + A shop operator has refunded all of this payment + """ + refunded +} + +""" +Input for the placeOrder mutation +""" +input PlaceOrderInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The order to be placed, if payment is accepted + """ + order: OrderInput! + + """ + The information necessary to pay. Collect this information from the shopper during a checkout flow. + You need not provide any payment input if the total is zero. + The total of all payment input `amount` fields must add up to the order total. The first payment + method where the `amount` field is `null` will be charged the remainder due. + """ + payments: [PaymentInput] +} + +""" +Response payload for the placeOrder mutation +""" +type PlaceOrderPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Orders that were created + """ + orders: [Order]! + + """ + If you are not logged in, this will be a token that can be used for future requests + """ + token: String +} + +""" +Represents Reaction Plugin +""" +type Plugin { + """ + Name of plugin + """ + name: String! + + """ + Version of plugin + """ + version: String +} + +""" +A Reaction product +""" +type Product { + """ + Product ID + """ + _id: ID! + + """ + The date and time at which this product was created + """ + createdAt: DateTime! + + """ + Hash to compare with publishedProductHash, to see if this product has changed since it was last published + """ + currentProductHash: String + + """ + The full product description, which may have newline characters in it + """ + description: String + + """ + True if this product has been deleted. Typically, deleted products are not returned in queries. + """ + isDeleted: Boolean! + + """ + True if this product should be shown to shoppers. Typically, non-visible products are not returned in queries. + """ + isVisible: Boolean! + + """ + All media for a product + """ + media( + """ + Determines whether variant media should be included in the product or not + """ + shouldIncludeVariantMedia: Boolean = true + ): [ImageInfo] + + """ + The product description to use for page `description` meta element in HTML + """ + metaDescription: String + + """ + Arbitrary additional metadata about this product + """ + metafields: [Metafield]! + + """ + The country of origin + """ + originCountry: String + + """ + Subtitle + """ + pageTitle: String + + """ + An arbitrary product type value, such as from an external system + """ + productType: String + + """ + The date and time at which this product was last published. If `null`, it has never been published. + """ + publishedAt: DateTime + + """ + Hash to compare with currentProductHash, to see if this product has changed since it was last published + """ + publishedProductHash: String + + """ + The shop to which this product belongs + """ + shop: Shop! + + """ + Whether this product will be shown in the generated sitemap + """ + shouldAppearInSitemap: Boolean + + """ + A URL-safe and human-readable string that uniquely identifies this product + """ + slug: String + + """ + Holds metadata specific to a specific social network service + """ + socialMetadata: [SocialMetadata] + + """ + When a shopper purchases this product, what types of fulfillment can they choose from? + """ + supportedFulfillmentTypes: [FulfillmentType]! + + """ + The list of tag IDs that have been applied to this product + """ + tagIds: [ID] + + """ + The list of tags that have been applied to this product + """ + tags( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, tags are sorted by ID. Set this to sort by one of the other allowed fields + """ + sortBy: TagSortByField = _id + ): TagConnection + + """ + Product title + """ + title: String + + """ + The date and time at which this product was last updated + """ + updatedAt: DateTime + + """ + A list of all variants for this product + """ + variants( + """ + Include hidden variants + """ + shouldIncludeHidden: Boolean = true + + """ + Include archived variants + """ + shouldIncludeArchived: Boolean = false + ): [ProductVariant]! + + """ + The product vendor or manufacturer, for display + """ + vendor: String + + """ + Price range + """ + price: ProductPriceRange @deprecated(reason: "Use `pricing`") + + """ + Pricing information + """ + pricing: ProductPricingInfo! +} + +""" +Product configuration data +""" +type ProductConfiguration { + """ + The Product ID + """ + productId: ID! + + """ + The ProductVariant ID + """ + productVariantId: ID! +} + +""" +Input that defines a single configuration of a product +""" +input ProductConfigurationInput { + """ + The Product ID + """ + productId: ID! + + """ + The ProductVariant ID + """ + productVariantId: ID! +} + +""" +Wraps a list of Products`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type ProductConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [ProductEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Product] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `Product` object +""" +type ProductEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The product + """ + node: Product +} + +""" +Mutation input for a product +""" +input ProductInput { + """ + Any string to use as the internal ID for a new product. Do not prefix or base64 encode this ID. + This field is allowed only when creating a product. If you include an ID for an update, you + will get an error. The string must also be different from any existing product, variant, or + option internal ID or you will get a duplicate ID error. If you do not include this when creating + a product, a random unique string is generated for you. + """ + _id: String + + """ + The full product description, which may have newline characters in it + """ + description: String + + """ + Facebook message + """ + facebookMsg: String + + """ + Google message + """ + googleplusMsg: String + + """ + True if this product has been deleted. Typically, deleted products are not returned in queries. + """ + isDeleted: Boolean + + """ + True if this product should be shown to shoppers. Typically, non-visible products are not returned in queries. + """ + isVisible: Boolean + + """ + The product description to use for page `description` meta element in HTML + """ + metaDescription: String + + """ + Arbitrary additional metadata about this product + """ + metafields: [MetafieldInput] + + """ + The country of origin + """ + originCountry: String + + """ + Subtitle + """ + pageTitle: String + + """ + Pinterest message + """ + pinterestMsg: String + + """ + An arbitrary product type value, such as from an external system + """ + productType: String + + """ + Whether this product will be shown in the generated sitemap + """ + shouldAppearInSitemap: Boolean + + """ + A URL-safe and human-readable string that uniquely identifies this product + """ + slug: String + + """ + When a shopper purchases this product, what types of fulfillment can they choose from? + """ + supportedFulfillmentTypes: [FulfillmentType] + + """ + The list of tag IDs that have been applied to this product + """ + tagIds: [ID] + + """ + Product title + """ + title: String + + """ + Twitter message + """ + twitterMsg: String + + """ + The product vendor or manufacturer, for display + """ + vendor: String +} + +""" +Product price range +""" +type ProductPriceRange { + """ + Maximum price in range + """ + max: Float + + """ + Minimum price in range + """ + min: Float + + """ + Price range display + """ + range: String +} + +""" +The product price or price range for a specific currency +""" +type ProductPricingInfo { + """ + A comparison price value, usually MSRP. If `price` is null, this will also be null. That is, + only purchasable variants will have a `compareAtPrice`. + """ + compareAtPrice: Money + + """ + The code for the currency these pricing details applies to + """ + currency: Currency! + + """ + Pricing converted to specified currency + """ + currencyExchangePricing( + """ + Code for the currency in which you want to see pricing info + """ + currencyCode: String! + ): CurrencyExchangeProductPricingInfo + + """ + UI should display this price. If a product has multiple potential prices depending on selected + variants and options, then this is a price range string such as "$3.95 - $6.99". It includes the currency + symbols. + """ + displayPrice: String! + + """ + The price of the most expensive possible variant+option combination + """ + maxPrice: Float! + + """ + The price of the least expensive possible variant+option combination + """ + minPrice: Float! + + """ + For variants with no options and for options, this will always be set to a price. For variants + with options and products, this will be `null`. There must be a price for a variant to be + added to a cart or purchased. Otherwise you would instead add one of its child options to a cart. + """ + price: Float +} + +""" +The fields by which you are allowed to sort any query that returns a `ProductConnection` +""" +enum ProductSortByField { + """ + Product ID + """ + _id + + """ + Date and time the product was created + """ + createdAt + + """ + Product title + """ + title + + """ + Date and time the product was last updated + """ + updatedAt +} + +""" +Input for adding tags to products in bulk +""" +input ProductTagsOperationInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + An array of product productIds to which an array of tags will be added + """ + productIds: [ID] + + """ + The shop id + """ + shopId: ID! + + """ + An array of tag ids to add to an array of products + """ + tagIds: [ID] +} + +""" +Response payload managing tags on products +""" +type ProductTagsOperationPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The number of products found + """ + foundCount: Int + + """ + The number of products for which a match was not found + """ + notFoundCount: Int + + """ + The number of products successfully updated + """ + updatedCount: Int + + """ + An array of write errors if any were generated + """ + writeErrors: [WriteError] +} + +""" +A Reaction product variant or option +""" +type ProductVariant { + """ + Variant ID + """ + _id: ID! + + """ + The attribute label describes the category of variant, for example, `Color` or `Size`. + In most cases this will be the same for all variants at the same level. + """ + attributeLabel: String + + """ + The product variant barcode value, if it has one + """ + barcode: String + + """ + The date and time at which this variant was created + """ + createdAt: DateTime + + """ + The height of the product variant, if it has physical dimensions + """ + height: Float + + """ + The position of this variant among other variants at the same level of the product-variant-option hierarchy + """ + index: Int + + """ + True if this variant was deleted. Deleted variants are not published to the catalog. + """ + isDeleted: Boolean! + + """ + True if this variant is visible. Hidden variants are not published to the catalog. + """ + isVisible: Boolean! + + """ + The length of the product, if it has physical dimensions + """ + length: Float + + """ + All media for a variant + """ + media: [ImageInfo] + + """ + Arbitrary additional metadata about this product + """ + metafields: [Metafield]! + + """ + The minimum quantity that must be added to a cart + """ + minOrderQuantity: Int + + """ + A short title to use for product detail select lists + """ + optionTitle: String + + """ + Child variants, if any + """ + options( + """ + Include hidden variants + """ + shouldIncludeHidden: Boolean = true + + """ + Include archived variants + """ + shouldIncludeArchived: Boolean = false + ): [ProductVariant]! + + """ + The country of origin + """ + originCountry: String + + """ + The shop to which this product variant belongs + """ + shop: Shop! + + """ + SKU of variant + """ + sku: String + + """ + The full variant title for use on cart, checkout, and order summaries and on invoices. + This fully describes the configured variant. For example, if this is an option with + `optionTitle` "Large", its parent variant has `optionTitle` `Red`, and the product + `title` is "Fancy T-Shirt", then this `title` will be something like `Fancy T-Shirt - Red - Large`. + """ + title: String + + """ + The date and time at which this product was last updated + """ + updatedAt: DateTime + + """ + The weight of the product on Earth, if it has physical dimensions + """ + weight: Float + + """ + The width of the product, if it has physical dimensions + """ + width: Float + + """ + Compare at price of the variant + """ + compareAtPrice: Float @deprecated(reason: "Use `pricing`") + + """ + Price of the variant + """ + price: Float @deprecated(reason: "Use `pricing`") + + """ + Pricing information + """ + pricing: ProductPricingInfo! + + """ + Whether this variant is taxable + """ + isTaxable: Boolean + + """ + Tax code + """ + taxCode: String + + """ + Tax description + """ + taxDescription: String +} + +""" +Mutation input for a product variant or option +""" +input ProductVariantInput { + """ + Any string to use as the internal ID for a new variant. Do not prefix or base64 encode this ID. + This field is allowed only when creating a variant. If you include an ID for an update, you + will get an error. The string must also be different from any existing product, variant, or + option internal ID or you will get a duplicate ID error. If you do not include this when creating + a variant, a random unique string is generated for you. + """ + _id: String + + """ + The attribute label describes the category of variant, for example, `Color` or `Size`. + In most cases this will be the same for all variants at the same level. + """ + attributeLabel: String + + """ + The product variant barcode value, if it has one + """ + barcode: String + + """ + The height of the product variant, if it has physical dimensions + """ + height: Float + + """ + The position of this variant among other variants at the same level of the product-variant-option hierarchy + """ + index: Int + + """ + True if this variant was deleted. Deleted variants are not published to the catalog. + """ + isDeleted: Boolean + + """ + True if this variant is visible. Hidden variants are not published to the catalog. + """ + isVisible: Boolean + + """ + The length of the product, if it has physical dimensions + """ + length: Float + + """ + Arbitrary additional metadata about this product + """ + metafields: [MetafieldInput] + + """ + The minimum quantity that must be added to a cart + """ + minOrderQuantity: Int + + """ + A short title to use for product detail select lists + """ + optionTitle: String + + """ + The country of origin + """ + originCountry: String + + """ + SKU of variant + """ + sku: String + + """ + The full variant title for use on cart, checkout, and order summaries and on invoices. + This fully describes the configured variant. For example, if this is an option with + `optionTitle` `Large`, its parent variant has `optionTitle` `Red`, and the product + `title` is `Fancy T-Shirt`, then this `title` will be something like `Fancy T-Shirt - Red - Large`. + """ + title: String + + """ + The weight of the product on Earth, if it has physical dimensions + """ + weight: Float + + """ + The width of the product, if it has physical dimensions + """ + width: Float + + """ + Variant compareAtPrice. DEPRECATED. Use the `updateProductVariantPrices` mutation to set product variant prices. + """ + compareAtPrice: Float + + """ + Variant price. DEPRECATED. Use the `updateProductVariantPrices` mutation to set product variant prices. + """ + price: Float + + """ + Whether this variant is taxable + """ + isTaxable: Boolean + + """ + Tax code + """ + taxCode: String + + """ + Tax description + """ + taxDescription: String +} + +""" +Mutation input for a product variant or option +""" +input ProductVariantPricesInput { + """ + Variant compareAtPrice + """ + compareAtPrice: Float + + """ + Variant price + """ + price: Float +} + +""" +Input for the `publishNavigationChanges` mutation +""" +input PublishNavigationChangesInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The ID of the navigation tree + """ + id: ID! + + """ + Shop ID of the navigation tree + """ + shopId: ID! +} + +""" +Response payload for the `publishNavigationChanges` mutation +""" +type PublishNavigationChangesPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The navigation tree with updated items + """ + navigationTree: NavigationTree +} + +type Query { + """ + A test query + """ + ping: String! + + """ + Returns the primary shop for the domain + """ + primaryShop: Shop + + """ + Returns the ID of the primary shop for the domain + """ + primaryShopId: ID + + """ + Returns a shop by ID + """ + shop( + """ + The shop ID + """ + id: ID! + ): Shop + + """ + Returns a shop by slug + """ + shopBySlug( + """ + The shop slug + """ + slug: String! + ): Shop + shops( + """ + Shop IDs to filter by + """ + shopIds: [ID] + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, groups are sorted by when they were created, oldest first. Set this to sort by one of the other allowed fields + """ + sortBy: GroupSortByField = createdAt + ): ShopConnection + + """ + Returns app settings that are not shop specific. Plugins extend the GlobalSettings type to support + whatever settings they need. + """ + globalSettings: GlobalSettings! + + """ + Returns app settings for a specific shop. Plugins extend the ShopSettings type to support + whatever settings they need. + """ + shopSettings( + """ + The shop to get app settings for + """ + shopId: ID! + ): ShopSettings! + + """ + Get a list of errors and suggested properly formatted addresses for an address. If no address + validation service is active for the shop, this will return as if the address is valid even + though no check actually occurred. + """ + addressValidation( + """ + Address to validate + """ + address: AddressInput! + + """ + Shop to use for determining what validation service to use + """ + shopId: ID! + ): AddressValidationResults! + + """ + Get a full list of all registered address validation services + """ + addressValidationServices: [AddressValidationService]! + + """ + Returns a list of defined address validation rules for a shop + """ + addressValidationRules( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + An optional list of service names, to get only rules that specify one of these services + """ + serviceNames: [String] + + """ + ID of the shop for which to get defined address validation rules + """ + shopId: ID! + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, rules are sorted by when they were created, oldest first. Set this to sort by one of the other allowed fields + """ + sortBy: AddressValidationRuleSortByField = createdAt + ): AddressValidationRuleConnection! + + """ + SystemInformation object + """ + systemInformation( + """ + Shop ID to use for shop-specific system information + """ + shopId: ID! + ): SystemInformation! + + """ + Retrieves a list of email templates + """ + emailTemplates( + """ + The shopId to which email templates belong to + """ + shopId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + ): TemplateConnection + + """ + Returns the account with the provided ID + """ + account( + """ + The account ID + """ + id: ID! + ): Account + + """ + Returns accounts optionally filtered by account groups + """ + accounts( + """ + Return only accounts in any of these groups + """ + groupIds: [ID] + + """ + Return accounts that aren't in any groups + """ + notInAnyGroups: Boolean + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, groups are sorted by when they were created, oldest first. Set this to sort by one of the other allowed fields + """ + sortBy: AccountSortByField = createdAt + ): AccountConnection! + + """ + Returns customer accounts + """ + customers( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, groups are sorted by when they were created, oldest first. Set this to sort by one of the other allowed fields + """ + sortBy: AccountSortByField = createdAt + ): AccountConnection! + + """ + Returns the account for the authenticated user + """ + viewer: Account + + """ + Returns a single group by ID. + """ + group( + """ + The group ID + """ + id: ID! + ): Group + + """ + Returns a list of groups for the shop with ID `shopId`, as a Relay-compatible connection. + """ + groups( + """ + Return groups for this shop + """ + shopId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, groups are sorted by when they were created, oldest first. Set this to sort by one of the other allowed fields + """ + sortBy: GroupSortByField = createdAt + ): GroupConnection + + """ + Returns all pending staff member invitations + """ + invitations( + """ + The shop IDs to get invitations for + """ + shopIds: [ID] + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, groups are sorted by when they were created, oldest first. Set this to sort by one of the other allowed fields + """ + sortBy: AccountSortByField = createdAt + ): InvitationConnection! + + """ + Returns a paged list of all roles associated with a shop + """ + roles( + """ + Return valid roles for this shop + """ + shopId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, roles are sorted alphabetically by name. Set this to sort by one of the other allowed fields + """ + sortBy: RoleSortByField = name + ): RoleConnection + + """ + Query for a single Product + """ + product( + """ + Product ID + """ + productId: ID! + + """ + Shop ID + """ + shopId: ID! + ): Product + + """ + Query for a list of Products + """ + products( + """ + Filter by archived + """ + isArchived: Boolean + + """ + Filter by visibility + """ + isVisible: Boolean + + """ + Filter by metafield key + """ + metafieldKey: String + + """ + Filter by metafield value + """ + metafieldValue: String + + """ + Filter by price range maximum value + """ + priceMax: Float + + """ + Filter by price range minimum value + """ + priceMin: Float + + """ + List of product IDs to filter by + """ + productIds: [ID] + + """ + Regex metch query string + """ + query: String + + """ + List of shop IDs to filter by + """ + shopIds: [ID]! + + """ + List of tag ids to filter by + """ + tagIds: [ID] + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + By default, products are sorted by createdAt. Set this to sort by one of the other allowed fields + """ + sortBy: ProductSortByField = createdAt + ): ProductConnection + + """ + Gets items from a shop catalog + """ + catalogItems( + """ + Provide a list of shop IDs from which you want to get catalog items + """ + shopIds: [ID]! + + """ + Optionally provide a list of tag IDs to further filter the item list + """ + tagIds: [ID] + + """ + Additional filters to apply + """ + booleanFilters: [CatalogBooleanFilter] + + """ + Optional text search query + """ + searchQuery: String + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + Provide a Currency code if sortBy is minPrice + """ + sortByPriceCurrencyCode: String + + """ + By default, items are sorted by when they were last updated, most recently updated first. Set this to sort by one of the other allowed fields + """ + sortBy: CatalogItemSortByField = updatedAt + ): CatalogItemConnection + + """ + Gets product from catalog + """ + catalogItemProduct( + """ + ID of the shop that owns the catalog product. Not required but highly recommended if you + have multiple shops and `slugOrId` is a slug because slugs are unique only within a shop. + """ + shopId: ID + + """ + Provide either a product ID or slug + """ + slugOrId: String + ): CatalogItemProduct + + """ + Gets an array of all vendors + """ + vendors( + """ + Optionally provide a list of shop IDs from which you want to get the vendors + """ + shopIds: [ID]! + + """ + Optionally provide a list of tag IDs to further filter the vendors + """ + tagIds: [ID] + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + ): VendorConnection + + """ + Returns a list of product in a tag + """ + productsByTagId( + """ + Shop that owns the tag + """ + shopId: ID! + + """ + The tag ID + """ + tagId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + ): TagProductConnection! + + """ + Returns a tag from a provided tag ID or slug. Tags with isVisible set to false are excluded by default. + """ + tag( + """ + Slug or ID of Tag + """ + slugOrId: String! + + """ + The shop to which this tag belongs + """ + shopId: ID! + + """ + Set to true if you want to include tags that have isVisible set to false + """ + shouldIncludeInvisible: Boolean = false + ): Tag + + """ + Returns a paged list of tags for a shop. You must include a shopId when querying. + """ + tags( + """ + Only tags associated with this shop will be returned + """ + shopId: ID! + + """ + If provided, this query will do a regex search using the provided filter data, and return only tags that match + """ + filter: String + + """ + Tags to exclude from results + """ + excludedTagIds: [ID] + + """ + If set, the query will return only top-level tags or only non-top-level tags. By default, both types of tags are returned. + """ + isTopLevel: Boolean + + """ + Set to true if you want soft deleted tags to be included in the response + """ + shouldIncludeDeleted: Boolean = false + + """ + Set to true if you want to include tags that have isVisible set to false + """ + shouldIncludeInvisible: Boolean = false + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, tags are sorted by position. Set this to sort by one of the other allowed fields + """ + sortBy: TagSortByField = position + ): TagConnection + + """ + Get the SimpleInventory info for a product configuration. Returns `null` if `updateSimpleInventory` + has never been called for this product configuration. + """ + simpleInventory( + """ + ID of the shop that owns the product + """ + shopId: ID! + + """ + The product configuration for which you want inventory info + """ + productConfiguration: ProductConfigurationInput! + ): SimpleInventoryInfo + + """ + Finds a cart by the cart ID and anonymous cart token. + """ + anonymousCartByCartId( + """ + The cart ID. Must be an anonymous cart (that is, one with no linked account). + """ + cartId: ID! + + """ + A valid anonymous cart access cartToken for this cart. This is returned when you create + an anonymous cart and should be stored securely in storefront client storage. + """ + cartToken: String! + ): Cart + + """ + Find a cart for a given account ID. + """ + accountCartByAccountId( + """ + Account that owns the cart + """ + accountId: ID! + + """ + Shop that owns the cart + """ + shopId: ID! + ): Cart + + """ + Get an order by its ID + """ + orderById( + """ + The order ID + """ + id: ID! + + """ + The shop that owns the order + """ + shopId: ID! + + """ + A valid anonymous access token for this order. Required if the order is not linked with an account. + """ + token: String + ): Order + + """ + Get all orders for a single account, optionally limited to certain shop IDs and certain orderStatus + """ + orders( + """ + Filters to apply to a list of orders + """ + filters: OrderFilterInput + + """ + Provide a list of shop IDs from which you want to get orders from + """ + shopIds: [ID] + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + By default, orders are sorted by when they were created, newest first. Set this to sort by one of the other allowed fields + """ + sortBy: OrdersSortByField = createdAt + ): OrderConnection! + + """ + Get all orders for a single account, optionally limited to certain shop IDs and certain orderStatus + """ + ordersByAccountId( + """ + Limit to orders placed by this account + """ + accountId: ID! + + """ + Limit to orders with one of these statuses + """ + orderStatus: [String] + + """ + Limit to orders owned by one of these shops + """ + shopIds: [ID]! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + By default, orders are sorted by when they were created, newest first. Set this to sort by one of the other allowed fields + """ + sortBy: OrdersByAccountIdSortByField = createdAt + ): OrdersByAccountIdConnection! + + """ + Get an order by its reference ID (the ID shown to customers) + """ + orderByReferenceId( + """ + The order reference ID (the ID shown to customers) + """ + id: ID! + + """ + The shop that owns the order + """ + shopId: ID! + + """ + A valid anonymous access token for this order. Required if the order is not linked with an account. + """ + token: String + ): Order + + """ + Get refunds applied to an order by order ID + """ + refunds( + """ + The order ID + """ + orderId: ID! + + """ + The shop that owns the order + """ + shopId: ID! + + """ + A valid anonymous access token for this order. Required if the order is not linked with an account. + """ + token: String + ): [Refund] + + """ + Get refunds applied to a specific payment by payment ID + """ + refundsByPaymentId( + """ + The order ID + """ + orderId: ID! + + """ + The ID of one of the payments made for this order + """ + paymentId: ID! + + """ + The shop that owns the order + """ + shopId: ID! + + """ + A valid anonymous access token for this order. Required if the order is not linked with an account. + """ + token: String + ): [Refund] + + """ + Get a list of all payment methods available during a checkout. This may filter by auth, + active/inactive, IP/region, shop, etc. To get the full list, use the `paymentMethods` + query with proper authorization. + """ + availablePaymentMethods( + """ + ID of the shop for which the order will be placed + """ + shopId: ID! + ): [PaymentMethod]! + + """ + Get a full list of all payment methods + """ + paymentMethods( + """ + The shop to get payment methods for + """ + shopId: ID! + ): [PaymentMethod]! + + """ + Gets discount codes + """ + discountCodes( + """ + Provide a shop ID from which you want to get discount codes + """ + shopId: ID! + + """ + Filters to apply to a discount codes query + """ + filters: DiscountCodeFilterInput + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + ): DiscountCodeConnection + + """ + Get the full list of surcharges. + """ + surcharges( + """ + ID of shop to get surcharges for + """ + shopId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + By default, surcharges are sorted by when they were created, newest first. Set this to sort by one of the other allowed fields + """ + sortBy: SurchargeSortByField = createdAt + ): SurchargeConnection! + + """ + Get a single surcharge definition by its ID + """ + surchargeById( + """ + ID of shop that owns the surcharge definition + """ + shopId: ID! + + """ + The surcharge ID + """ + surchargeId: ID! + ): Surcharge + + """ + Get a flat rate fulfillment method + """ + flatRateFulfillmentMethod( + """ + Fulfillment method id + """ + methodId: ID! + + """ + Shop ID + """ + shopId: ID! + ): FlatRateFulfillmentMethod! + + """ + Get a flat rate fulfillment methods + """ + flatRateFulfillmentMethods( + """ + Shop ID + """ + shopId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + ): FlatRateFulfillmentMethodConnection! + + """ + Get the full list of flat rate fulfillment method restrictions. + """ + getFlatRateFulfillmentRestrictions( + """ + Shop to get restrictions for + """ + shopId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + By default, restrictions are sorted by when they were created, newest first. Set this to sort by one of the other allowed fields + """ + sortBy: FlatRateFulfillmentRestrictionSortByField = createdAt + ): FlatRateFulfillmentRestrictionConnection! + + """ + Get a single flat rate fulfillment method restriction. + """ + getFlatRateFulfillmentRestriction( + """ + The restriction ID + """ + restrictionId: ID! + + """ + Shop that owns the restriction + """ + shopId: ID! + ): FlatRateFulfillmentRestriction + + """ + List all tax codes supported by the current active tax service for the shop + """ + taxCodes( + """ + The shop to use for getting the list of active tax services + """ + shopId: ID! + ): [TaxCode]! + + """ + Get a full list of all tax services for the shop + """ + taxServices( + """ + The shop to use for getting the list of all tax services + """ + shopId: ID! + ): [TaxService]! + + """ + Gets tax rates + """ + taxRates( + """ + Provide a shp ID from which you want to get tax rates + """ + shopId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + ): TaxRateConnection + + """ + Returns a navigation tree by its ID in the specified language + """ + navigationTreeById( + """ + The ID of the navigation tee + """ + id: ID! + + """ + Navigation language + """ + language: String! + + """ + The ID of the shop to load navigation tree for + """ + shopId: ID! + + """ + Set to true if you want to include secondary navigation items along with the primary items + """ + shouldIncludeSecondary: Boolean = false + ): NavigationTree + + """ + Returns the navigation items for a shop + """ + navigationItemsByShopId( + """ + The ID of the shop to load navigation items for + """ + shopId: ID! + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = desc + + """ + By default, items are sorted by when they were created, newest first. Set this to sort by one of the other allowed fields + """ + sortBy: NavigationItemSortByField = createdAt + ): NavigationItemConnection + + """ + Returns Sitemap object for a shop based on the handle param + """ + sitemap( + """ + The sitemap handle + """ + handle: String! + + """ + Shop URL + """ + shopUrl: String! + ): Sitemap + twoFactorSecret: TwoFactorSecretKey + getUser: User +} + +""" +A numeric rate, with its corresponding percent values +""" +type Rate { + """ + The rate + """ + amount: Float! + + """ + The percent as a preformatted string with percent symbol included + """ + displayPercent: String! + + """ + The percent (rate x 100) + """ + percent: Float! +} + +""" +Input for the `recalculateReservedSimpleInventory` mutation +""" +input RecalculateReservedSimpleInventoryInput { + """ + The product and chosen options this info applies to + """ + productConfiguration: ProductConfigurationInput! + + """ + Shop that owns the product + """ + shopId: ID! +} + +""" +Response payload for the `updateSimpleInventory` mutation +""" +type RecalculateReservedSimpleInventoryPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated inventory info + """ + inventoryInfo: SimpleInventoryInfo! +} + +""" +Input for the `reconcileCarts` mutation call +""" +input ReconcileCartsInput { + """ + An anonymous cart ID + """ + anonymousCartId: ID! + + """ + An anonymous cart token + """ + cartToken: String! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + If both an anonymous cart and a cart for the authenticated account are found, how do we combine them? + Default mode is `merge`, where all anonymous items are moved into the account cart along with existing + account cart items, and quantities are combined. + """ + mode: CartReconciliationMode + + """ + The ID of the shop that owns both carts + """ + shopId: ID! +} + +""" +The payload returned from the `reconcileCarts` mutation call +""" +type ReconcileCartsPayload { + """ + The account cart, potentially modified + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +A refund of a payment on an order +""" +type Refund implements Node { + """ + The refund ID + """ + _id: ID! + + """ + The amount of the refund + """ + amount: Money! + + """ + The date and time at which the refund was created + """ + createdAt: DateTime! + + """ + The display name of the payment refunded to + """ + paymentDisplayName: String! + + """ + The ID of the payment this refund is applied to + """ + paymentId: ID! + + """ + The reason for the refund + """ + reason: String +} + +""" +Describes which address should be removed from which account +""" +input RemoveAccountAddressBookEntryInput { + """ + The account ID + """ + accountId: ID! + + """ + The address ID + """ + addressId: ID! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String +} + +""" +The response from the `removeAccountAddressBookEntry` mutation +""" +type RemoveAccountAddressBookEntryPayload { + """ + The removed address + """ + address: Address + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Defines which email address should be removed from which account +""" +input RemoveAccountEmailRecordInput { + """ + The account ID, which defaults to the viewer account + """ + accountId: ID + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The email address to remove + """ + email: Email! +} + +""" +The response from the `removeAccountEmailRecord` mutation +""" +type RemoveAccountEmailRecordPayload { + """ + The account, with updated `emailRecords` + """ + account: Account + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Defines a group and account that should be unlinked +""" +input RemoveAccountFromGroupInput { + """ + The account ID + """ + accountId: ID! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The group ID + """ + groupId: ID! +} + +""" +The response from the `removeAccountFromGroup` mutation +""" +type RemoveAccountFromGroupPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The removed group + """ + group: Group! +} + +""" +The details for removing a group +""" +input RemoveAccountGroupInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The group ID + """ + groupId: ID! + + """ + The ID of the shop this group belongs to + """ + shopId: ID +} + +""" +The response from the `removeGroup` mutation +""" +type RemoveAccountGroupPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The removed group + """ + group: Group +} + +""" +Input for the `removeCartItems` mutation +""" +input RemoveCartItemsInput { + """ + The cart ID + """ + cartId: ID! + + """ + Array of items to remove from the cart. + """ + cartItemIds: [ID]! + + """ + If this cart is anonymous, provide the `cartToken` that was returned in the `CreateCartPayload` + """ + cartToken: String + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String +} + +""" +The payload returned from the `removeCartItems` mutation call +""" +type RemoveCartItemsPayload { + """ + The modified cart + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input for an `RemoveDiscountCodeFromCartInput` +""" +input RemoveDiscountCodeFromCartInput { + """ + Cart to add discount to + """ + cartId: ID! + + """ + ID of the discount you want to remove from the cart + """ + discountId: ID! + + """ + Shop cart belongs to + """ + shopId: ID! + + """ + Cart token, if anonymous + """ + token: String +} + +""" +Response from the `removeDiscountCodeFromCart` mutation +""" +type RemoveDiscountCodeFromCartPayload { + """ + The updated cart with discount code removed + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input for `removeTag` mutation +""" +input RemoveTagInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of tag to delete + """ + id: ID! + + """ + The shop that owns the tag + """ + shopId: ID! +} + +""" +Response payload for `removeTag` mutation +""" +type RemoveTagPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The deleted tag + """ + tag: Tag! +} + +""" +Restriction type +""" +enum RestrictionTypeEnum { + """ + Allow + """ + allow + + """ + Deny + """ + deny +} + +""" +Input for `retryFailedEmail` mutation +""" +input RetryFailedEmailInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of Email Job to retry + """ + jobId: ID! + + """ + Shop ID of Email Job + """ + shopId: ID! +} + +""" +Response payload for `retryFailedEmail` mutation +""" +type RetryFailedEmailPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Email retry status + """ + emailSent: Boolean! +} + +""" +Valid payment risk levels +""" +enum RiskLevel { + """ + An elevated risk level for a payment + """ + elevated + + """ + The highest risk level for a payment + """ + highest + + """ + A normal risk level for a payment + """ + normal +} + +""" +Represents a named role +""" +type Role implements Node { + """ + The role ID + """ + _id: ID! + + """ + A unique name for the role + """ + name: String! +} + +""" +Wraps a list of `Roles`, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type RoleConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [RoleEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Role] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `Role` object +""" +type RoleEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The role + """ + node: Role +} + +""" +The fields by which you are allowed to sort any query that returns an `RoleConnection` +""" +enum RoleSortByField { + """ + Role ID + """ + _id + + """ + Role name + """ + name +} + +""" +Input needed to select a fulfillment option for a single fulfillment group on a cart +""" +input SelectFulfillmentOptionForGroupInput { + """ + The cart to select this option for + """ + cartId: ID! + + """ + The token for the cart, required if it is an anonymous cart + """ + cartToken: String + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The group to select this option for + """ + fulfillmentGroupId: ID! + + """ + The fulfillment method ID from the option the shopper selected + """ + fulfillmentMethodId: ID! +} + +""" +The response from the `selectFulfillmentOptionForGroup` mutation +""" +type SelectFulfillmentOptionForGroupPayload { + """ + The updated Cart + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Describes which email should be sent a password reset link +""" +input SendResetAccountPasswordEmailInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The email address of the account to send reset email to + """ + email: String! +} + +""" +The response from the `sendResetAccountPasswordEmail` mutation +""" +type SendResetAccountPasswordEmailPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The email address of the account to send reset email to + """ + email: String! +} + +""" +Defines which email address should be set as the default for which account +""" +input SetAccountDefaultEmailInput { + """ + The account ID, which defaults to the viewer account + """ + accountId: ID + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The email address to set as default + """ + email: Email! +} + +""" +The response from the `setAccountDefaultEmail` mutation +""" +type SetAccountDefaultEmailPayload { + """ + The account, with updated `emailRecords` + """ + account: Account + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input for the `setEmailOnAnonymousCart` mutation call +""" +input SetEmailOnAnonymousCartInput { + """ + An anonymous cart ID + """ + cartId: ID! + + """ + Provide the `cartToken` that was returned in the `CreateCartPayload` + """ + cartToken: String! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The email address to associate with this cart. This address is used for order communication and + other fulfillment purposes. + """ + email: String! +} + +""" +The payload returned from the `setEmailOnAnonymousCart` mutation call +""" +type SetEmailOnAnonymousCartPayload { + """ + The modified cart + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input needed when setting the shipping address on a cart +""" +input SetShippingAddressOnCartInput { + """ + The shipping address + """ + address: AddressInput! + + """ + If set, this will be saved as the Address._id. Otherwise an ID will be generated. + """ + addressId: String + + """ + The cart to set shipping address on + """ + cartId: ID! + + """ + The token for the cart, required if it is an anonymous cart + """ + cartToken: String + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String +} + +""" +The response from the `setShippingAddressOnCart` mutation +""" +type SetShippingAddressOnCartPayload { + """ + The updated Cart + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input for `setTagHeroMedia` mutation +""" +input SetTagHeroMediaInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + File record document + """ + fileRecord: JSONObject + + """ + ID of tag to add the hero image record to + """ + id: ID! + + """ + The shop that owns the tag + """ + shopId: ID! +} + +""" +Response payload for `setTagHeroMedia` mutation +""" +type SetTagHeroMediaPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Tag the hero image was added to + """ + tag: Tag! +} + +""" +Extra data for an order fulfillment group with type `shipping` +""" +type ShippingOrderFulfillmentGroupData { + """ + The address to ship to + """ + shippingAddress: Address! +} + +""" +A shipping parcel +""" +type ShippingParcel { + """ + Containers + """ + containers: String + + """ + Distance unit + """ + distanceUnit: DistanceUnit + + """ + Height + """ + height: Float + + """ + Length + """ + length: Float + + """ + Mass unit + """ + massUnit: MassUnit + + """ + Weight + """ + weight: Float + + """ + Width + """ + width: Float +} + +""" +Represents a Reaction shop +""" +type Shop implements Node { + """ + The shop ID + """ + _id: ID! + + """ + An the shop's default address + """ + addressBook: [Address] + + """ + Whether to allow user to checkout without creating an account + """ + allowGuestCheckout: Boolean + + """ + The base unit of length + """ + baseUOL: String + + """ + The base unit of Measure + """ + baseUOM: String + + """ + URLs for various shop assets in various sizes + """ + brandAssets: ShopBrandAssets + + """ + The default shop currency + """ + currency: Currency! + + """ + Default parcel size for this shop + """ + defaultParcelSize: ShopParcelSize + + """ + Shop description + """ + description: String + + """ + The shop's default email record + """ + emails: [EmailRecord] + + """ + Shop's keywords + """ + keywords: String + + """ + Shop default language + """ + language: String! + + """ + Shop name + """ + name: String! + + """ + Returns URLs for shop logos + """ + shopLogoUrls: ShopLogoUrls + + """ + Shop's type + """ + shopType: String + + """ + Shop's slug + """ + slug: String + + """ + Returns URLs for various storefront routes + """ + storefrontUrls: StorefrontUrls + + """ + Shop default timezone + """ + timezone: String + + """ + The shop's units of length + """ + unitsOfLength: [UnitOfLength] + + """ + The shop's units of measure + """ + unitsOfMeasure: [UnitOfMeasure] + + """ + Returns a list of groups for this shop, as a Relay-compatible connection. + """ + groups( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, groups are sorted by when they were created, oldest first. Set this to sort by one of the other allowed fields + """ + sortBy: GroupSortByField = createdAt + ): GroupConnection + + """ + Returns a list of roles for this shop, as a Relay-compatible connection. + """ + roles( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, roles are sorted alphabetically by name. Set this to sort by one of the other allowed fields + """ + sortBy: RoleSortByField = name + ): RoleConnection + + """ + Returns a paged list of tags for this shop + """ + tags( + """ + If set, the query will return only top-level tags or only non-top-level tags. By default, both types of tags are returned. + """ + isTopLevel: Boolean + + """ + Set to true if you want soft deleted tags to be included in the response + """ + shouldIncludeDeleted: Boolean = false + + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, tags are sorted by position. Set this to sort by one of the other allowed fields + """ + sortBy: TagSortByField = position + ): TagConnection + + """ + The default navigation tree for this shop + """ + defaultNavigationTree( + """ + Navigation tree language + """ + language: String! + + """ + Whether to include secondary navigation items + """ + shouldIncludeSecondary: Boolean = false + ): NavigationTree + + """ + The ID of the shop's default navigation tree + """ + defaultNavigationTreeId: String +} + +""" +URLs for various shop assets in various sizes +""" +type ShopBrandAssets { + """ + URLs for the navigation bar brand logo image + """ + navbarBrandImage: ImageSizes + + """ + Internal navigation bar brand logo image ID + """ + navbarBrandImageId: String +} + +""" +Wraps a list of `Shops`, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type ShopConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [ShopEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Shop] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is an `Shop` object +""" +type ShopEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The Shop + """ + node: Shop +} + +""" +Shop logo URLs +""" +type ShopLogoUrls { + """ + The primary logo URL for this shop. Setting this overrides any uploaded logo. + """ + primaryShopLogoUrl: String +} + +""" +Shop Logo URLs to provide for the updateShop mutation +""" +input ShopLogoUrlsInput { + """ + The primary logo URL for this shop. Setting this overrides any uploaded logo. + """ + primaryShopLogoUrl: String +} + +""" +Parcel size +""" +type ShopParcelSize { + """ + Parcel height + """ + height: Float + + """ + Parcel length + """ + length: Float + + """ + Parcel weight + """ + weight: Float + + """ + Parcel width + """ + width: Float +} + +""" +Parcel size input +""" +input ShopParcelSizeInput { + """ + Parcel height + """ + height: Float + + """ + Parcel length + """ + length: Float + + """ + Parcel weight + """ + weight: Float + + """ + Parcel width + """ + width: Float +} + +""" +App settings for a specific shop. Plugins extend the ShopSettings type to support +whatever settings they need. +""" +type ShopSettings { + """ + A fake setting necessary until some plugin extends this with a real setting + """ + doNotUse: String + + """ + If there is no known inventory for a product configuration, this setting determines + whether that product configuration can be sold and should appear to be available. + """ + canSellVariantWithoutInventory: Boolean! + + """ + If `false` no defined shipping rates will be used when fulfillment + quotes are requested for a cart or order. A quick way to disable the entire + `reaction-shipping-rates` plugin temporarily. + """ + isShippingRatesFulfillmentEnabled: Boolean + + """ + The default value to use for `taxCode` property of a product + """ + defaultTaxCode: String + + """ + The name of the tax service to fall back to if the primary tax service is down. + This will match the `name` field of one of the services returned by the `taxServices` + query. + """ + fallbackTaxServiceName: String + + """ + The name of the tax service to use for calculating taxes on carts and orders. + This will match the `name` field of one of the services returned by the `taxServices` + query. + """ + primaryTaxServiceName: String + + """ + Whether a navigation item added to the navigation tree should be visible only to + admins by default. + """ + shouldNavigationTreeItemsBeAdminOnly: Boolean! + + """ + Whether a navigation item added to the navigation tree should be + public API/Storefront visible by default. + """ + shouldNavigationTreeItemsBePubliclyVisible: Boolean! + + """ + Whether a navigation item added to the navigation tree should be a secondary + navigation item by default. + """ + shouldNavigationTreeItemsBeSecondaryNavOnly: Boolean! + + """ + This setting controls how often the sitemaps for the shop will be rebuilt + """ + sitemapRefreshPeriod: String! +} + +""" +Updates for app settings that are not shop specific. Plugins extend +this input type to support whatever settings they need. All fields +must be optional. +""" +input ShopSettingsUpdates { + """ + Do not use this field + """ + doNotUse: String + + """ + If there is no known inventory for a product configuration, this setting determines + whether that product configuration can be sold and should appear to be available. + """ + canSellVariantWithoutInventory: Boolean + + """ + Set to `false` to prevent any defined shipping rates from being used when fulfillment + quotes are requested for a cart or order. A quick way to disable the entire + `reaction-shipping-rates` plugin temporarily. + """ + isShippingRatesFulfillmentEnabled: Boolean + + """ + The default value to use for `taxCode` property of a product + """ + defaultTaxCode: String + + """ + Optionally, set the name of the tax service to fall back to if the primary tax service is down. + This must match the `name` field of one of the services returned by the `taxServices` query. + """ + fallbackTaxServiceName: String + + """ + Set the name of the tax service to use for calculating taxes on carts and orders. + This will match the `name` field of one of the services returned by the `taxServices` + query. There will be no taxes charged for any carts or orders if this is not set. + """ + primaryTaxServiceName: String + + """ + Whether a navigation item added to the navigation tree should be visible only to + admins by default. + """ + shouldNavigationTreeItemsBeAdminOnly: Boolean + + """ + Whether a navigation item added to the navigation tree should be + public API/Storefront visible by default. + """ + shouldNavigationTreeItemsBePubliclyVisible: Boolean + + """ + Whether a navigation item added to the navigation tree should be a secondary + navigation item by default. + """ + shouldNavigationTreeItemsBeSecondaryNavOnly: Boolean + + """ + This setting controls how often the sitemaps for the shop will be rebuilt + """ + sitemapRefreshPeriod: String +} + +""" +Inventory info for a specific product configuration. For inventory managed by the SimpleInventory plugin. +""" +type SimpleInventoryInfo { + """ + Whether to allow ordering this product configuration when there is insufficient quantity available + """ + canBackorder: Boolean + + """ + Current quantity of this product configuration in stock + """ + inventoryInStock: Int + + """ + Current quantity of this product configuration unavailable for ordering. This value is calculated + by the system based on this product variant being in not-yet-approved orders. + """ + inventoryReserved: Int + + """ + Whether the SimpleInventory plugin should manage inventory for this product configuration + """ + isEnabled: Boolean + + """ + The "low quantity" flag will be applied to this product configuration when the available quantity + is at or below this threshold + """ + lowInventoryWarningThreshold: Int + + """ + The product and chosen options this info applies to + """ + productConfiguration: ProductConfiguration! +} + +""" +Generated sitemap XML for a single shop +""" +type Sitemap { + """ + Date created + """ + createdAt: Date! + + """ + The sitemap handle + """ + handle: String! + + """ + The shop ID + """ + shopId: String! + + """ + The Sitemap XML content + """ + xml: String! +} + +""" +Holds metadata specific to a specific social network service +""" +type SocialMetadata { + """ + Default share message to use when sharing this product on this social network + """ + message: String + + """ + Which social network is this metadata for + """ + service: SocialNetwork +} + +""" +The list of currently supported social network identifiers +""" +enum SocialNetwork { + """ + Facebook + """ + facebook + + """ + Google+ + """ + googleplus + + """ + Pinterest + """ + pinterest + + """ + Twitter + """ + twitter +} + +""" +The order in which the connection results should be sorted, based on the sortBy field. +""" +enum SortOrder { + """ + ascending + """ + asc + + """ + descending + """ + desc +} + +""" +Input for the splitOrderItem mutation +""" +input SplitOrderItemInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of the item order you want to split + """ + itemId: ID! + + """ + The quantity that will be transferred to a new order item on the same fulfillment group. + """ + newItemQuantity: Int! + + """ + ID of the order that has the item you want to split + """ + orderId: ID! +} + +""" +Response payload for the splitOrderItem mutation +""" +type SplitOrderItemPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The ID of the new order item that was created + """ + newItemId: ID! + + """ + The updated order + """ + order: Order! +} + +""" +Storefront route URLs +""" +type StorefrontUrls { + """ + Storefront Account Profile URL (can include `:accountId` in string) + """ + storefrontAccountProfileUrl: String + + """ + Storefront Home URL + """ + storefrontHomeUrl: String + + """ + Storefront login URL + """ + storefrontLoginUrl: String + + """ + Storefront single order URL (can include `:orderReferenceId` and `:orderToken` in string) + """ + storefrontOrderUrl: String + + """ + Storefront orders URL (can include `:accountId` in string) + """ + storefrontOrdersUrl: String +} + +""" +Storefront route URLs to provide for the updateShop mutation +""" +input StorefrontUrlsInput { + """ + Storefront Account Profile URL (can include `:accountId` in string) + """ + storefrontAccountProfileUrl: String + + """ + Storefront Home URL + """ + storefrontHomeUrl: String + + """ + Storefront login URL + """ + storefrontLoginUrl: String + + """ + Storefront single order URL (can include `:orderReferenceId` and `:orderToken` in string) + """ + storefrontOrderUrl: String + + """ + Storefront orders URL (can include `:accountId` in string) + """ + storefrontOrdersUrl: String +} + +""" +Data for a Stripe card payment +""" +type StripeCardPaymentData { + """ + The Stripe charge ID + """ + chargeId: String! + + """ + The Stripe customer ID, if a Stripe customer exists for this charge + """ + customerId: String +} + +type Subscription { + """ + A test subscription that returns an incremented number every 1 second for 10 seconds + """ + tick: Int! +} + +""" +An address suggestion returned from an address validation service +""" +type SuggestedAddress { + """ + The street address / first line + """ + address1: String! + + """ + Optional second line + """ + address2: String + + """ + City + """ + city: String! + + """ + Country + """ + country: String! + + """ + Postal code + """ + postal: String! + + """ + Region. For example, a U.S. state + """ + region: String! +} + +""" +Defines a surcharge for surchargeById and surcharges query. +""" +type Surcharge implements Node { + """ + The surcharge ID. + """ + _id: ID! + + """ + Amount. + """ + amount: Money! + + """ + Attribute restrictions. + """ + attributes: [SurchargeAttributeRestrictions] + + """ + The date and time at which this surcharge was created + """ + createdAt: DateTime! + + """ + Destination restrictions. + """ + destination: SurchargeDestinationRestrictions + + """ + Message translated into provided / default language. + """ + message( + """ + The language in which you want the message. If no translation is available for this language, + it will be in the default language of the related shop. + """ + language: String! + ): String! + + """ + Messages provided with content and all languages + """ + messagesByLanguage: [SurchargeMessagesByLanguage] + + """ + Method IDs to apply this surcharge to. + """ + methodIds: [ID] + + """ + The shop ID + """ + shopId: ID! + + """ + The type of this surcharge. Allowed types `surcharge`. + """ + type: SurchargeTypeEnum! + + """ + The date and time at which this surcharge was last updated + """ + updatedAt: DateTime +} + +""" +Attribute Restrictions attached to a Surcharge +""" +type SurchargeAttributeRestrictions { + """ + The operator to use for value comparison + """ + operator: String + + """ + The property to check + """ + property: String + + """ + The type of this property + """ + propertyType: SurchargePropertyType + + """ + The value to check for + """ + value: String +} + +""" +Input to add a surcharge attribute restriction +""" +input SurchargeAttributeRestrictionsInput { + """ + The operator to use for value comparison + """ + operator: String + + """ + The property to check + """ + property: String + + """ + The type of this property + """ + propertyType: SurchargePropertyType + + """ + The value to check for + """ + value: String +} + +""" +Wraps a list of `Surcharge`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type SurchargeConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [SurchargeEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Surcharge] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + Total count for all pages + """ + totalCount: Int! +} + +""" +Destination restrictions attached to a surcharge. If multiple of `country`, +`region`, and `postal` are set, there is an AND relationship. +""" +type SurchargeDestinationRestrictions { + """ + Restrict for any of these destination countries + """ + country: [String] + + """ + Restrict for any of these destination postal codes + """ + postal: [String] + + """ + Restrict for any of these destination regions + """ + region: [String] +} + +""" +Input to add a surcharge destination restriction +""" +input SurchargeDestinationRestrictionsInput { + """ + Restrict for any of these destination countries + """ + country: [String] + + """ + Restrict for any of these destination postal codes + """ + postal: [String] + + """ + Restrict for any of these destination regions + """ + region: [String] +} + +""" +A connection edge in which each node is a `Surcharge` object +""" +type SurchargeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The surcharge + """ + node: Surcharge +} + +""" +Defines a surcharge. +""" +input SurchargeInput { + """ + Amount. + """ + amount: Float! + + """ + Attribute restrictions. + """ + attributes: [SurchargeAttributeRestrictionsInput] + + """ + Destination restrictions. + """ + destination: SurchargeDestinationRestrictionsInput + + """ + Messages by language. + """ + messagesByLanguage: [MessagesByLanguageInput]! + + """ + Method IDs to apply this surcharge to. + """ + methodIds: [ID] + + """ + The type of this surcharge. Allowed types are `surcharge`. + """ + type: SurchargeTypeEnum! +} + +""" +Object that includes translated content and language of translation +""" +type SurchargeMessagesByLanguage { + """ + The message for this language + """ + content: String! + + """ + The language code + """ + language: String! +} + +""" +A list of the possible property types for surcharges +""" +enum SurchargePropertyType { + """ + Boolean + """ + bool + + """ + Float + """ + float + + """ + Integer + """ + int + + """ + String + """ + string +} + +""" +Allowed values for surcharge `sortBy` parameter +""" +enum SurchargeSortByField { + """ + The date the surcharge definition was created + """ + createdAt +} + +""" +Allowed values for surcharge type +""" +enum SurchargeTypeEnum { + """ + Surcharge + """ + surcharge +} + +""" +Represents Reaction System Infomation +""" +type SystemInformation { + """ + Core api version + """ + apiVersion: String! + + """ + Mongo version + """ + mongoVersion: DatabaseInformation! + + """ + Plugins installed with name, version information + """ + plugins: [Plugin] +} + +""" +Represents a single tag +""" +type Tag implements Node & Deletable { + """ + The tag ID + """ + _id: ID! + + """ + The date and time at which this tag was created + """ + createdAt: DateTime! + + """ + A string of the title to be displayed on a Tag Listing Page + """ + displayTitle: String + + """ + A list of the IDs of top products in this tag + """ + featuredProductIds: [ID] + + """ + A string containing the hero image url for a Tag Listing Page + """ + heroMediaUrl: String + + """ + If `true`, this object should be considered deleted. Soft deleted objects are not + returned in query results unless you explicitly ask for them. + """ + isDeleted: Boolean! + + """ + If `true`, this tag should be shown at the top level of the tag hierarchy + """ + isTopLevel: Boolean! + + """ + If `true`, this tag's Tag Listing Page should be visible to the public + """ + isVisible: Boolean! + + """ + Arbitrary additional metadata about this tag + """ + metafields: [Metafield] + + """ + The display name for the tag. This is unique within a given shop. + """ + name: String! + + """ + The tag's position relative to other tags at the same level of the tag hierarchy + """ + position: Int + + """ + The shop to which this tag belongs + """ + shop: Shop! + + """ + A unique URL-safe string representing this tag for links + """ + slug: String + + """ + A list of the IDs of tags that have this tag as their parent in the tag hierarchy, in the user-defined order + """ + subTagIds: [ID]! + + """ + The date and time at which this tag was last updated + """ + updatedAt: DateTime! + + """ + A paged list of tags that have this tag as their parent in the tag hierarchy. Currently only three levels are supported. + """ + subTags( + """ + Return only results that come after this cursor. Use this with `first` to specify the number of results to return. + """ + after: ConnectionCursor + + """ + Return only results that come before this cursor. Use this with `last` to specify the number of results to return. + """ + before: ConnectionCursor + + """ + Return at most this many results. This parameter may be used with either `after` or `offset` parameters. + """ + first: ConnectionLimitInt + + """ + Return at most this many results. This parameter may be used with the `before` parameter. + """ + last: ConnectionLimitInt + + """ + Return only results that come after the Nth result. This parameter may be used with the `first` parameter. + """ + offset: Int + + """ + Return results sorted in this order + """ + sortOrder: SortOrder = asc + + """ + By default, tags are sorted by position. Set this to sort by one of the other allowed fields + """ + sortBy: TagSortByField = position + ): TagConnection +} + +""" +Wraps a list of `Tags`, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type TagConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [TagEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Tag] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `Tag` object +""" +type TagEdge implements NodeEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The tag + """ + node: Tag +} + +""" +A tag product +""" +type TagProduct { + """ + The product id + """ + _id: ID! + + """ + The date and time at which this CatalogProduct was created, which is when the related product was first published + """ + createdAt: DateTime! + + """ + Position of the product + """ + position: Int + + """ + The title of the product + """ + title: String +} + +""" +Wraps a list of `TagProduct`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type TagProductConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [TagProductEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [TagProduct] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `TagProduct` object +""" +type TagProductEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The tag product + """ + node: TagProduct +} + +""" +The fields by which you are allowed to sort any query that returns a `TagConnection` +""" +enum TagSortByField { + """ + Tag ID + """ + _id + + """ + Date and time the tag was created + """ + createdAt + + """ + Tag name + """ + name + + """ + Tag position + """ + position + + """ + Date and time the tag was last updated + """ + updatedAt +} + +""" +A tax code that may be used on a product to indicate proper taxation category +""" +type TaxCode { + """ + The code + """ + code: String! + + """ + Short description of what types of products the code is for + """ + label: String! +} + +""" +A single calculated tax for a cart, order group, cart item, or order item +""" +type TaxRate { + """ + Tax rate ID + """ + _id: ID! + + """ + An optional country code to limit where this tax is applied, in conjunction with `sourcing` field + """ + country: String + + """ + An optional postal code to limit where this tax is applied, in conjunction with `sourcing` field + """ + postal: String + + """ + The tax rate. For example, 0.05 for a 5% sales tax. + """ + rate: Float! + + """ + An optional region (e.g., state) to limit where this tax is applied, in conjunction with `sourcing` field + """ + region: String + + """ + The shop to which this TaxRate belongs + """ + shop: Shop! + + """ + Whether the `country`, `postal`, and `region` filters apply to the origin address or the destination address + """ + sourcing: TaxSource! + + """ + An optional tax code, to apply this tax rate to only products that have this tax code + """ + taxCode: String +} + +""" +Wraps a list of TaxRate`s, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type TaxRateConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [TaxRateEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [TaxRate] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `TaxRate` object +""" +type TaxRateEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The tax rate + """ + node: TaxRate +} + +""" +A service registered by a tax plugin, that provides tax codes and calculations +""" +type TaxService { + """ + Human-readable display name + """ + displayName: String! + + """ + The tax service name. Any valid name that has been registered by a tax plugin. + """ + name: String! + + """ + Name of the plugin that added the tax service + """ + pluginName: String! +} + +""" +Tax sources +""" +enum TaxSource { + """ + Tax is applied when the destination matches the tax jurisdiction + """ + destination + + """ + Tax is applied when the origin matches the tax jurisdiction + """ + origin +} + +""" +A summary of tax-related calculations for a cart or order group +""" +type TaxSummary { + """ + The time at which taxes were last calculated for the cart or order group + """ + calculatedAt: DateTime! + + """ + The name of the tax service that last calculated taxes for the cart or order group + """ + calculatedByTaxServiceName: String + + """ + A reference ID for the external system that calculated the taxes + """ + referenceId: String + + """ + Total tax calculated by the active tax service + """ + tax: Money! + + """ + Amount that was deemed subject to any taxes by the active tax service + """ + taxableAmount: Money! + + """ + Full list of all taxes that were calculated by the active tax service for the cart or order group + """ + taxes: [CalculatedTax]! +} + +""" +Represents a Template +""" +type Template implements Node { + """ + The shop ID + """ + _id: ID! + + """ + Email template language + """ + language: String + + """ + Email template name + """ + name: String + + """ + The shop that owns the template + """ + shopId: ID! + + """ + Email template string + """ + subject: String + + """ + Email template body or html text + """ + template: String + + """ + Email template title + """ + title: String +} + +""" +Wraps a list of Templates, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type TemplateConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [TemplateEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Template] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a `Template` object +""" +type TemplateEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The email template + """ + node: Template +} + +type Tokens { + refreshToken: String + accessToken: String +} + +type TwoFactorSecretKey { + ascii: String + base32: String + hex: String + qr_code_ascii: String + qr_code_hex: String + qr_code_base32: String + google_auth_qr: String + otpauth_url: String +} + +input TwoFactorSecretKeyInput { + ascii: String + base32: String + hex: String + qr_code_ascii: String + qr_code_hex: String + qr_code_base32: String + google_auth_qr: String + otpauth_url: String +} + +""" +Units of length +""" +type UnitOfLength { + """ + Whether this unit of length is the default + """ + default: Boolean + + """ + The name of the unit of length + """ + label: String + + """ + Unit of length + """ + uol: String +} + +""" +Units of measure +""" +type UnitOfMeasure { + """ + Whether this unit of measure is the default + """ + default: Boolean + + """ + The name of the unit of measure + """ + label: String + + """ + Unit of measure + """ + uom: String +} + +""" +Describes changes that should be applied to one of the addresses for an account +""" +input UpdateAccountAddressBookEntryInput { + """ + The account ID + """ + accountId: ID! + + """ + The address ID + """ + addressId: ID! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + If present, make this address the default address of this type + """ + type: AddressType + + """ + The address changes to apply + """ + updates: AddressInput! +} + +""" +The response from the `updateAccountAddressBookEntry` mutation +""" +type UpdateAccountAddressBookEntryPayload { + """ + The updated address + """ + address: Address + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +The details for updating a group +""" +input UpdateAccountGroupInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The changes to apply to the group + """ + group: UpdateGroupInput! + + """ + The group ID + """ + groupId: ID! + + """ + The ID of the shop this group belongs to + """ + shopId: ID +} + +""" +The response from the `updateAccountGroup` mutation +""" +type UpdateAccountGroupPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated group + """ + group: Group +} + +""" +Describes an account update +""" +input UpdateAccountInput { + """ + The account ID, which defaults to the viewer account + """ + accountId: ID + + """ + Bio to display on profile + """ + bio: String + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The preferred currency code used by this account + """ + currencyCode: String + + """ + The first name of the person this account represents + """ + firstName: String + + """ + The preferred language (code) used by this account + """ + language: String + + """ + The last name of the person this account represents + """ + lastName: String + + """ + The full name of the person this account represents + """ + name: String + + """ + Some note about this account + """ + note: String + + """ + URL of picture to display on profile + """ + picture: String + + """ + Username + """ + username: String +} + +""" +The response from the `updateAccount` mutation +""" +type UpdateAccountPayload { + """ + The updated account + """ + account: Account! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input for the `updateAddressValidationRule` mutation +""" +input UpdateAddressValidationRuleInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Country codes for which this service is enabled. `null` means all, while an empty array means none. + """ + countryCodes: [String] + + """ + ID of the rule you want to update + """ + ruleId: ID! + + """ + The name of one of the installed validation services. Use `addressValidationServices` + query to get a list, and then use the `name` field value from one of them. + """ + serviceName: String! + + """ + Shop ID of the rule you want to update. This is not something you can modify. + """ + shopId: ID! +} + +""" +Payload for the `updateAddressValidationRule` mutation +""" +type UpdateAddressValidationRulePayload { + """ + Updated address validation rule + """ + addressValidationRule: AddressValidationRule! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +input UpdateAdminUIAccessInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The account IDs to update + """ + accountIds: [String]! + + """ + The shop IDs to unassign or assign to the accounts + """ + shopIds: [String]! +} + +type UpdateAdminUIAccessPayload { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The up to date account objects + """ + accounts: [Account] +} + +""" +Input for the `updateCartItem` mutation +""" +input UpdateCartItemInput { + """ + The cart item ID + """ + cartItemId: ID! + + """ + New absolute value for specified cart item's quantity. Not an incremental value. + """ + quantity: Int! +} + +""" +Input for the `updateCartItemsQuantity` mutation +""" +input UpdateCartItemsQuantityInput { + """ + The cart ID + """ + cartId: ID! + + """ + If this cart is anonymous, provide the `cartToken` that was returned in the `CreateCartPayload` + """ + cartToken: String + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Array of cart item quantities to update. + """ + items: [UpdateCartItemInput]! +} + +""" +The payload returned from the `updateCartItemsQuantity` mutation call +""" +type UpdateCartItemsQuantityPayload { + """ + The modified cart + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Describes the input for updating a discount code +""" +input UpdateDiscountCodeInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The discount code to update + """ + discountCode: DiscountCodeInput + + """ + The ID of the discount code to update + """ + discountCodeId: ID! + + """ + The shop ID of the discount code to update + """ + shopId: ID! +} + +""" +The response from the `updateDiscountCode` mutation +""" +type UpdateDiscountCodePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated discount code + """ + discountCode: DiscountCode +} + +""" +Input for the `updateFlatRateFulfillmentMethod` mutation +""" +input UpdateFlatRateFulfillmentMethodInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The updated method. Pass the whole updated method object without the ID. + """ + method: FlatRateFulfillmentMethodInput! + + """ + The ID of the flat rate fulfillment method you want to update + """ + methodId: ID! + + """ + The shop that owns the method + """ + shopId: ID! +} + +""" +Response from the `updateFlatRateFulfillmentMethod` mutation +""" +type UpdateFlatRateFulfillmentMethodPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated fulfillment method + """ + method: FlatRateFulfillmentMethod! +} + +""" +Input for the `updateFlatRateFulfillmentRestriction` mutation +""" +input UpdateFlatRateFulfillmentRestrictionInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The updated flat rate fulfillment method restriction. Pass the whole updated restriction object without the ID. + """ + restriction: FlatRateFulfillmentRestrictionInput! + + """ + The ID of the flat rate fulfillment method restriction you want to update + """ + restrictionId: ID! + + """ + The shop that owns the flat rate fulfillment method restriction + """ + shopId: ID! +} + +""" +Response from the `updateFlatRateFulfillmentMethod` mutation +""" +type UpdateFlatRateFulfillmentRestrictionPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated flat rate fulfillment method restriction + """ + restriction: FlatRateFulfillmentRestriction! +} + +""" +A request to update the available fulfillment options for a single fulfillment group +""" +input UpdateFulfillmentOptionsForGroupInput { + """ + The cart to update fulfillment options for + """ + cartId: ID! + + """ + The token for the cart, required if it is an anonymous cart + """ + cartToken: String + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The group to update fulfillment options for + """ + fulfillmentGroupId: ID! +} + +""" +The response from the `updateFulfillmentOptionsForGroup` mutation +""" +type UpdateFulfillmentOptionsForGroupPayload { + """ + The updated Cart + """ + cart: Cart! + + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String +} + +""" +Input for the `updateGlobalSettings` mutation +""" +input UpdateGlobalSettingsInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Updated settings values. Only includes settings to be changed. + """ + settingsUpdates: GlobalSettingsUpdates! +} + +""" +Response payload for the `updateGlobalSettings` mutation +""" +type UpdateGlobalSettingsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Updated global settings + """ + globalSettings: GlobalSettings! +} + +""" +Fields to update for an existing account group +""" +input UpdateGroupInput { + """ + A free text description of this group + """ + description: String + + """ + A unique name for the group + """ + name: String + + """ + A unique URL-safe string representing this group + """ + slug: String + + """ + A list of the account permissions implied by membership in this group + """ + permissions: [String] +} + +input UpdateGroupsForAccountsInput { + """ + The account IDs + """ + accountIds: [ID]! + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The group IDs + """ + groupIds: [ID]! +} + +type UpdateGroupsForAccountsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The accounts that were modified + """ + accounts: [Account]! +} + +""" +Input for the updateMediaRecordPriority mutation +""" +input UpdateMediaRecordPriorityInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of MediaRecord to update + """ + mediaRecordId: ID! + + """ + New priority value + """ + priority: Int! + + """ + ID of shop that owns this MediaRecord + """ + shopId: ID! +} + +""" +Response payload for the updateMediaRecordPriority mutation +""" +type UpdateMediaRecordPriorityPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated MediaRecord + """ + mediaRecord: MediaRecord! +} + +""" +Input for the `updateNavigationItem` mutation +""" +input UpdateNavigationItemInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The ID of the navigation item to update + """ + id: ID! + + """ + The field updates to apply + """ + navigationItem: NavigationItemInput! + + """ + The ID of the shop navigation item belongs to + """ + shopId: ID! +} + +""" +Response payload for the `updateNavigationItem` mutation +""" +type UpdateNavigationItemPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated navigation item + """ + navigationItem: NavigationItem +} + +""" +Input for the `updateNavigationTree` mutation +""" +input UpdateNavigationTreeInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The ID of the navigation tree to update + """ + id: ID! + + """ + The field updates to apply + """ + navigationTree: NavigationTreeInput! + + """ + The ID of the shop navigation item belongs to + """ + shopId: ID! +} + +""" +Response payload for the `updateNavigationTree` mutation +""" +type UpdateNavigationTreePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated navigation tree + """ + navigationTree: NavigationTree +} + +""" +Input for the updateOrderFulfillmentGroup mutation +""" +input UpdateOrderFulfillmentGroupInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of the order fulfillment group to update + """ + orderFulfillmentGroupId: ID! + + """ + ID of the order to update + """ + orderId: ID! + + """ + Set the current order fulfillment group status to this + """ + status: String + + """ + Set this as the current order fulfillment group shipment tracking reference + """ + tracking: String + + """ + Set this as the current order fulfillment group shipment tracking URL + """ + trackingUrl: String +} + +""" +Response payload for the updateOrderFulfillmentGroup mutation +""" +type UpdateOrderFulfillmentGroupPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated order + """ + order: Order! +} + +""" +Input for the updateOrder mutation +""" +input UpdateOrderInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Set the order email to this + """ + email: String + + """ + ID of the order to update + """ + orderId: ID! + + """ + Set the current order status to this + """ + status: String +} + +""" +Response payload for the updateOrder mutation +""" +type UpdateOrderPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated order + """ + order: Order! +} + +""" +Input for the `updateProduct` mutation +""" +input UpdateProductInput { + """ + Product input + """ + product: ProductInput! + + """ + ID of product to update + """ + productId: ID! + + """ + ID of shop that owns the product to update + """ + shopId: ID! +} + +""" +Response payload of `updateProduct` mutation +""" +type UpdateProductPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Updated product + """ + product: Product! +} + +""" +Input for the `updateProductVariantField` mutation +""" +input UpdateProductVariantInput { + """ + ID of shop that owns the variant to update + """ + shopId: ID! + + """ + Variant input + """ + variant: ProductVariantInput! + + """ + ID of variant to update + """ + variantId: ID! +} + +""" +Response payload of `updateProductVariantField` mutation +""" +type UpdateProductVariantPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Updated variant + """ + variant: ProductVariant! +} + +""" +Input for the `updateProductVariantField` mutation +""" +input UpdateProductVariantPricesInput { + """ + Prices to update + """ + prices: ProductVariantPricesInput! + + """ + ID of shop that owns the variant to update + """ + shopId: ID! + + """ + ID of variant to update + """ + variantId: ID! +} + +""" +Response payload of `updateProductVariantPricesField` mutation +""" +type UpdateProductVariantPricesPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Updated variant + """ + variant: ProductVariant! +} + +""" +Input for the `updateProductsVisibility` mutation +""" +input UpdateProductsVisibilityInput { + """ + The desired visibility + """ + isVisible: Boolean! + + """ + Array of product ids to update + """ + productIds: [ID]! + + """ + ID of shop the products belong to + """ + shopId: ID! +} + +""" +Response payload for `updateProductsVisibility` mutation +""" +type UpdateProductsVisibilityPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The number of products that were updated successfully + """ + updatedCount: Int +} + +""" +Input parameters for the updateShop mutation +""" +input UpdateShopInput { + """ + An address book entry to set the primary shop's address + """ + addressBook: [AddressInput] + + """ + Whether to allow user to checkout without creating an account + """ + allowGuestCheckout: Boolean + + """ + The base unit of length + """ + baseUOL: String + + """ + The base unit of Measure + """ + baseUOM: String + + """ + ID of media record to be used as the brand asset + """ + brandAssets: ID + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The shop's currency + """ + currency: String + + """ + Default parcel size used for this shop + """ + defaultParcelSize: ShopParcelSizeInput + + """ + The shop's description + """ + description: String + + """ + The shops primary email address + """ + emails: [EmailRecordInput] + + """ + The shop's keywords + """ + keywords: String + + """ + The shop's language + """ + language: String + + """ + The shop's name + """ + name: String + + """ + The ID of the shop to update + """ + shopId: ID! + + """ + Object of shop logo urls + """ + shopLogoUrls: ShopLogoUrlsInput + + """ + Shop's slug + """ + slug: String + + """ + Object of storefront routes urls + """ + storefrontUrls: StorefrontUrlsInput + + """ + The shop's timezone + """ + timezone: String +} + +""" +The response from the `updateShop` mutation +""" +type UpdateShopPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The shop which was updated + """ + shop: Shop! +} + +""" +Input for the `updateShopSettings` mutation +""" +input UpdateShopSettingsInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Updated settings values. Only includes settings to be changed. + """ + settingsUpdates: ShopSettingsUpdates! + + """ + The ID of the shop to update some settings for + """ + shopId: ID! +} + +""" +Response payload for the `updateShopSettings` mutation +""" +type UpdateShopSettingsPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + Updated shop settings + """ + shopSettings: ShopSettings! +} + +""" +Input for the `updateSimpleInventory` mutation. In addition to `shopId`, at least one field to update is required. +""" +input UpdateSimpleInventoryInput { + """ + Whether to allow ordering this product configuration when there is insufficient quantity available. + Set this to `true` or `false` if you want to update it. + """ + canBackorder: Boolean + + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Current quantity of this product configuration in stock. Set this to an integer if you want to update it. + """ + inventoryInStock: Int + + """ + Whether the SimpleInventory plugin should manage inventory for this product configuration. + Set this to `true` or `false` if you want to update it. + """ + isEnabled: Boolean + + """ + The "low quantity" flag will be applied to this product configuration when the available quantity + is at or below this threshold. Set this to an integer if you want to update it. + """ + lowInventoryWarningThreshold: Int + + """ + The product and chosen options this info applies to + """ + productConfiguration: ProductConfigurationInput! + + """ + Shop that owns the product + """ + shopId: ID! +} + +""" +Response payload for the `updateSimpleInventory` mutation +""" +type UpdateSimpleInventoryPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated inventory info + """ + inventoryInfo: SimpleInventoryInfo! +} + +""" +Input for the `updateSurcharge` mutation +""" +input UpdateSurchargeInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + The shop that owns the method + """ + shopId: ID! + + """ + The updated surcharge. Pass the whole updated surcharge object without the ID. + """ + surcharge: SurchargeInput! + + """ + The ID of the flat rate fulfillment surcharge you want to update + """ + surchargeId: ID! +} + +""" +Response from the `updateFlatRateFulfillmentMethod` mutation +""" +type UpdateSurchargePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated fulfillment surcharge + """ + surcharge: Surcharge! +} + +""" +Input for `updateTag` mutation +""" +input UpdateTagInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + Title to display to customers + """ + displayTitle: String + + """ + A list of the IDs of top products in this tag + """ + featuredProductIds: [ID] + + """ + Hero media URL + """ + heroMediaUrl: String + + """ + ID of rule to modify + """ + id: ID! + + """ + Whether the tag is visible + """ + isVisible: Boolean! + + """ + Tag metafields + """ + metafields: [MetafieldInput] + + """ + Unique name of the tag + """ + name: String! + + """ + The shop that owns the tag + """ + shopId: ID! + + """ + The tag slug. If left blank, the name will be slugified and saved as the slug + """ + slug: String +} + +""" +Response payload for `updateTag` mutation +""" +type UpdateTagPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated tag + """ + tag: Tag! +} + +""" +The input for updating a tax rate. Note that missing values will cause the field to be cleared, so +send all optional fields with every request unless they aren't currently set or you intend to clear them. +""" +input UpdateTaxRateInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + An optional country code to limit where this tax is applied based on destination address + """ + country: String + + """ + An optional postal code to limit where this tax is applied based on destination address + """ + postal: String + + """ + The tax rate. For example, 0.05 for a 5% sales tax. + """ + rate: Float! + + """ + An optional region (e.g., state) to limit where this tax is applied based on destination address + """ + region: String + + """ + Shop ID + """ + shopId: ID! + + """ + Whether the `country`, `postal`, and `region` filters apply to the origin address or the destination address + """ + sourcing: TaxSource + + """ + An optional tax code, to apply this tax rate to only products that have this tax code + """ + taxCode: String + + """ + ID of the tax rate you want to update + """ + taxRateId: ID! +} + +""" +The response from the `updateTaxRate` mutation +""" +type UpdateTaxRatePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated tax rate + """ + taxRate: TaxRate! +} + +""" +Input for `updateTemplate` mutation +""" +input UpdateTemplateInput { + """ + An optional string identifying the mutation call, which will be returned in the response payload + """ + clientMutationId: String + + """ + ID of template to modify + """ + id: ID! + + """ + The shop that owns the template + """ + shopId: ID! + + """ + Email template string + """ + subject: String + + """ + Email template body or html text + """ + template: String + + """ + Email template title + """ + title: String +} + +""" +Response payload for `updateTemplate` mutation +""" +type UpdateTemplatePayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + The updated template + """ + template: Template! +} + +type User { + id: ID! + emails: [EmailRecord!] + username: String +} + +input UserInput { + id: ID + email: String + username: String +} + +type Vendor { + """ + The name of the vendor + """ + name: String +} + +""" +Wraps an array of vendors, providing pagination cursors and information. + +For information about what Relay-compatible connections are and how to use them, see the following articles: +- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections) +- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm) +- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html) +""" +type VendorConnection { + """ + The list of nodes that match the query, wrapped in an edge to provide a cursor string for each + """ + edges: [VendorEdge] + + """ + You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has, + if you know you will not need to paginate the results. + """ + nodes: [Vendor] + + """ + Information to help a client request the next or previous page + """ + pageInfo: PageInfo! + + """ + The total number of nodes that match your query + """ + totalCount: Int! +} + +""" +A connection edge in which each node is a String representing a vendor +""" +type VendorEdge { + """ + The cursor that represents this node in the paginated results + """ + cursor: ConnectionCursor! + + """ + The vendor + """ + node: Vendor +} + +""" +Input for an `VerifySMTPEmailSettingsInput` +""" +input VerifySMTPEmailSettingsInput { + """ + The ID of the shop this setting belongs to + """ + shopId: ID! +} + +""" +Response payload for the verifySMTPEmailSettings mutation +""" +type VerifySMTPEmailSettingsInputPayload { + """ + The same string you sent with the mutation params, for matching mutation calls with their responses + """ + clientMutationId: String + + """ + True if the SMTP connection was made and authentication was successful. + """ + isVerified: Boolean! +} + +""" +A bulk write error type +""" +type WriteError { + """ + The documentId(_id) on which the error occurred + """ + documentId: Int + + """ + Error message for a documentId + """ + errorMsg: String +} diff --git a/framework/reactioncommerce/types.ts b/framework/reactioncommerce/types.ts new file mode 100644 index 00000000..b6bbae8b --- /dev/null +++ b/framework/reactioncommerce/types.ts @@ -0,0 +1,38 @@ +import * as Core from '@commerce/types' + +export interface Cart extends Core.Cart { + id: string + lineItems: LineItem[] +} + +export interface LineItem extends Core.LineItem { + options: any[] +} + +/** + * Cart mutations + */ + +export type OptionSelections = { + option_id: number + option_value: number | string +} + +export type CartItemBody = Core.CartItemBody & { + productId: string // The product id is always required for BC + optionSelections?: OptionSelections +} + +export type GetCartHandlerBody = Core.GetCartHandlerBody + +export type AddCartItemBody = Core.AddCartItemBody<CartItemBody> + +export type AddCartItemHandlerBody = Core.AddCartItemHandlerBody<CartItemBody> + +export type UpdateCartItemBody = Core.UpdateCartItemBody<CartItemBody> + +export type UpdateCartItemHandlerBody = Core.UpdateCartItemHandlerBody<CartItemBody> + +export type RemoveCartItemBody = Core.RemoveCartItemBody + +export type RemoveCartItemHandlerBody = Core.RemoveCartItemHandlerBody diff --git a/framework/reactioncommerce/utils/customer-token.ts b/framework/reactioncommerce/utils/customer-token.ts new file mode 100644 index 00000000..6546eedc --- /dev/null +++ b/framework/reactioncommerce/utils/customer-token.ts @@ -0,0 +1,25 @@ +import Cookies, { CookieAttributes } from 'js-cookie' +import { + REACTION_COOKIE_EXPIRE, + REACTION_CUSTOMER_TOKEN_COOKIE, +} from '../const' + +export const getCustomerToken = () => + Cookies.get(REACTION_CUSTOMER_TOKEN_COOKIE) + +export const setCustomerToken = ( + token: string | null, + options?: CookieAttributes +) => { + if (!token) { + Cookies.remove(REACTION_CUSTOMER_TOKEN_COOKIE) + } else { + Cookies.set( + REACTION_CUSTOMER_TOKEN_COOKIE, + token, + options ?? { + expires: REACTION_COOKIE_EXPIRE, + } + ) + } +} diff --git a/framework/reactioncommerce/utils/get-anonymous-cart-token.ts b/framework/reactioncommerce/utils/get-anonymous-cart-token.ts new file mode 100644 index 00000000..2c6c478e --- /dev/null +++ b/framework/reactioncommerce/utils/get-anonymous-cart-token.ts @@ -0,0 +1,8 @@ +import Cookies from 'js-cookie' +import { REACTION_ANONYMOUS_CART_TOKEN_COOKIE } from '../const' + +const getAnonymousCartToken = (id?: string) => { + return id ?? Cookies.get(REACTION_ANONYMOUS_CART_TOKEN_COOKIE) +} + +export default getAnonymousCartToken diff --git a/framework/reactioncommerce/utils/get-cart-id.ts b/framework/reactioncommerce/utils/get-cart-id.ts new file mode 100644 index 00000000..14a4ce05 --- /dev/null +++ b/framework/reactioncommerce/utils/get-cart-id.ts @@ -0,0 +1,8 @@ +import Cookies from 'js-cookie' +import { REACTION_CART_ID_COOKIE } from '../const' + +const getCartId = (id?: string) => { + return id ?? Cookies.get(REACTION_CART_ID_COOKIE) +} + +export default getCartId diff --git a/framework/reactioncommerce/utils/get-categories.ts b/framework/reactioncommerce/utils/get-categories.ts new file mode 100644 index 00000000..170e5cb2 --- /dev/null +++ b/framework/reactioncommerce/utils/get-categories.ts @@ -0,0 +1,34 @@ +import { ReactionCommerceConfig } from '../api' +import { CollectionEdge, TagEdge } from '../schema' +import getTagsQuery from './queries/get-all-collections-query' + +export type Category = { + entityId: string + name: string + path: string +} + +const getCategories = async ( + config: ReactionCommerceConfig +): Promise<Tag[]> => { + const { data } = await config.fetch(getTagsQuery, { + variables: { + first: 250, + shopId: config.shopId, + }, + }) + + return ( + data.tags?.edges?.map( + ({ + node: { _id: entityId, displayTitle: name, slug: handle }, + }: TagEdge) => ({ + entityId, + name, + path: `/${handle}`, + }) + ) ?? [] + ) +} + +export default getCategories diff --git a/framework/reactioncommerce/utils/get-search-variables.ts b/framework/reactioncommerce/utils/get-search-variables.ts new file mode 100644 index 00000000..6e6cb40b --- /dev/null +++ b/framework/reactioncommerce/utils/get-search-variables.ts @@ -0,0 +1,34 @@ +import getSortVariables from './get-sort-variables' +import type { SearchProductsInput } from '../product/use-search' + +export const getSearchVariables = ({ + brandId, + search, + categoryId, + sort, +}: SearchProductsInput) => { + let searchQuery = '' + let tagIdsParam = {} + + if (search) { + searchQuery += search + } + + if (brandId) { + searchQuery += `${search ? ' ' : ''}${brandId}` + } + + if (categoryId) { + tagIdsParam = { + tagIds: [categoryId], + } + } + + return { + searchQuery, + ...tagIdsParam, + ...getSortVariables(sort, !!categoryId), + } +} + +export default getSearchVariables diff --git a/framework/reactioncommerce/utils/get-sort-variables.ts b/framework/reactioncommerce/utils/get-sort-variables.ts new file mode 100644 index 00000000..b8cdeec5 --- /dev/null +++ b/framework/reactioncommerce/utils/get-sort-variables.ts @@ -0,0 +1,32 @@ +const getSortVariables = (sort?: string, isCategory = false) => { + let output = {} + switch (sort) { + case 'price-asc': + output = { + sortKey: 'PRICE', + reverse: false, + } + break + case 'price-desc': + output = { + sortKey: 'PRICE', + reverse: true, + } + break + case 'trending-desc': + output = { + sortKey: 'BEST_SELLING', + reverse: false, + } + break + case 'latest-desc': + output = { + sortKey: isCategory ? 'CREATED' : 'CREATED_AT', + reverse: true, + } + break + } + return output +} + +export default getSortVariables diff --git a/framework/reactioncommerce/utils/get-vendors.ts b/framework/reactioncommerce/utils/get-vendors.ts new file mode 100644 index 00000000..55b8b1cf --- /dev/null +++ b/framework/reactioncommerce/utils/get-vendors.ts @@ -0,0 +1,39 @@ +import { ReactionCommerceConfig } from '../api' +import getAllProductVendors from './queries/get-all-product-vendors-query' +import { Vendor } from '@framework/schema' + +export type Brand = { + entityId: string + name: string + path: string +} + +export type BrandEdge = { + node: Brand +} + +export type Brands = BrandEdge[] + +const getVendors = async ( + config: ReactionCommerceConfig +): Promise<BrandEdge[]> => { + const { + data: { vendors }, + } = await config.fetch(getAllProductVendors, { + variables: { + shopIds: [config.shopId], + }, + }) + + let vendorsStrings: string[] = vendors.nodes?.map(({ name }: Vendor) => name) + + return [...new Set(vendorsStrings)].map((v) => ({ + node: { + entityId: v, + name: v, + path: `brands/${v}`, + }, + })) +} + +export default getVendors diff --git a/framework/reactioncommerce/utils/handle-fetch-response.ts b/framework/reactioncommerce/utils/handle-fetch-response.ts new file mode 100644 index 00000000..b67ca45a --- /dev/null +++ b/framework/reactioncommerce/utils/handle-fetch-response.ts @@ -0,0 +1,27 @@ +import { FetcherError } from '@commerce/utils/errors' + +export function getError(errors: any[], status: number) { + errors = errors ?? [{ message: 'Failed to fetch Reaction Commerce API' }] + return new FetcherError({ errors, status }) +} + +export async function getAsyncError(res: Response) { + const data = await res.json() + return getError(data.errors, res.status) +} + +const handleFetchResponse = async (res: Response) => { + if (res.ok) { + const { data, errors } = await res.json() + + if (errors && errors.length) { + throw getError(errors, res.status) + } + + return data + } + + throw await getAsyncError(res) +} + +export default handleFetchResponse diff --git a/framework/reactioncommerce/utils/index.ts b/framework/reactioncommerce/utils/index.ts new file mode 100644 index 00000000..6cdf16cf --- /dev/null +++ b/framework/reactioncommerce/utils/index.ts @@ -0,0 +1,11 @@ +export { default as handleFetchResponse } from './handle-fetch-response' +export { default as getSearchVariables } from './get-search-variables' +export { default as getSortVariables } from './get-sort-variables' +export { default as getVendors } from './get-vendors' +export { default as getCategories } from './get-categories' +export { default as getAnonymousCartToken } from './get-anonymous-cart-token' +export { default as getAnonymousCartId } from './get-cart-id' +export * from './queries' +export * from './mutations' +export * from './normalize' +export * from './customer-token' diff --git a/framework/reactioncommerce/utils/mutations/add-cart-items.ts b/framework/reactioncommerce/utils/mutations/add-cart-items.ts new file mode 100644 index 00000000..d8ed1acc --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/add-cart-items.ts @@ -0,0 +1,24 @@ +import { + cartPayloadFragment, + incorrectPriceFailureDetailsFragment, + minOrderQuantityFailureDetailsFragment, +} from '@framework/utils/queries/get-cart-query' + +const addCartItemsMutation = ` + mutation addCartItemsMutation($input: AddCartItemsInput!) { + addCartItems(input: $input) { + cart { + ${cartPayloadFragment} + } + incorrectPriceFailures { + ${incorrectPriceFailureDetailsFragment} + } + minOrderQuantityFailures { + ${minOrderQuantityFailureDetailsFragment} + } + clientMutationId + } + } +` + +export default addCartItemsMutation diff --git a/framework/reactioncommerce/utils/mutations/authenticate.ts b/framework/reactioncommerce/utils/mutations/authenticate.ts new file mode 100644 index 00000000..418275ee --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/authenticate.ts @@ -0,0 +1,15 @@ +const authenticateMutation = /* GraphQL */ ` + mutation authenticate( + $serviceName: String! + $params: AuthenticateParamsInput! + ) { + authenticate(serviceName: $serviceName, params: $params) { + sessionId + tokens { + refreshToken + accessToken + } + } + } +` +export default authenticateMutation diff --git a/framework/reactioncommerce/utils/mutations/create-cart.ts b/framework/reactioncommerce/utils/mutations/create-cart.ts new file mode 100644 index 00000000..dc76c300 --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/create-cart.ts @@ -0,0 +1,24 @@ +import { + cartPayloadFragment, + incorrectPriceFailureDetailsFragment, + minOrderQuantityFailureDetailsFragment, +} from '@framework/utils/queries/get-cart-query' + +const createCartMutation = /* GraphQL */ ` + mutation createCartMutation($input: CreateCartInput!) { + createCart(input: $input) { + cart { + ${cartPayloadFragment} + } + incorrectPriceFailures { + ${incorrectPriceFailureDetailsFragment} + } + minOrderQuantityFailures { + ${minOrderQuantityFailureDetailsFragment} + } + clientMutationId + token + } + } +` +export default createCartMutation diff --git a/framework/reactioncommerce/utils/mutations/create-user.ts b/framework/reactioncommerce/utils/mutations/create-user.ts new file mode 100644 index 00000000..04818e77 --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/create-user.ts @@ -0,0 +1,13 @@ +const createUserMutation = /* GraphQL */ ` + mutation createUser($input: CreateUserInput!) { + createUser(user: $input) { + loginResult { + tokens { + refreshToken + accessToken + } + } + } + } +` +export default createUserMutation diff --git a/framework/reactioncommerce/utils/mutations/index.ts b/framework/reactioncommerce/utils/mutations/index.ts new file mode 100644 index 00000000..f27a0d97 --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/index.ts @@ -0,0 +1,7 @@ +export { default as addCartItemsMutation } from './add-cart-items' +export { default as createUserMutation } from './create-user' +export { default as createCartMutation } from './create-cart' +export { default as authenticateMutation } from './authenticate' +export { default as logoutMutation } from './logout' +export { default as removeCartItemsMutation } from './remove-cart-items' +export { default as updateCartItemsQuantityMutation } from './update-cart-items-quantity' diff --git a/framework/reactioncommerce/utils/mutations/logout.ts b/framework/reactioncommerce/utils/mutations/logout.ts new file mode 100644 index 00000000..bbc289f2 --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/logout.ts @@ -0,0 +1,7 @@ +const logoutMutation = /* GraphQL */ ` + mutation logout { + logout + } +` + +export default logoutMutation diff --git a/framework/reactioncommerce/utils/mutations/reconcile-carts.ts b/framework/reactioncommerce/utils/mutations/reconcile-carts.ts new file mode 100644 index 00000000..b5fcae90 --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/reconcile-carts.ts @@ -0,0 +1,13 @@ +import { cartPayloadFragment } from '@framework/utils/queries/get-cart-query' + +const reconcileCartsMutation = ` + mutation reconcileCartsMutation($input: ReconcileCartsInput!) { + reconcileCarts(input: $input) { + cart { + ${cartPayloadFragment} + } + } + } +` + +export default reconcileCartsMutation diff --git a/framework/reactioncommerce/utils/mutations/remove-cart-items.ts b/framework/reactioncommerce/utils/mutations/remove-cart-items.ts new file mode 100644 index 00000000..83564ddc --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/remove-cart-items.ts @@ -0,0 +1,13 @@ +import { cartPayloadFragment } from '@framework/utils/queries/get-cart-query' + +const updateCartItemsQuantityMutation = ` + mutation removeCartItemsMutation($input: RemoveCartItemsInput!) { + removeCartItems(input: $input) { + cart { + ${cartPayloadFragment} + } + } + } +` + +export default updateCartItemsQuantityMutation diff --git a/framework/reactioncommerce/utils/mutations/update-cart-items-quantity.ts b/framework/reactioncommerce/utils/mutations/update-cart-items-quantity.ts new file mode 100644 index 00000000..df7cdfda --- /dev/null +++ b/framework/reactioncommerce/utils/mutations/update-cart-items-quantity.ts @@ -0,0 +1,13 @@ +import { cartPayloadFragment } from '@framework/utils/queries/get-cart-query' + +const updateCartItemsQuantityMutation = ` + mutation UpdateCartItemsQuantity($updateCartItemsQuantityInput: UpdateCartItemsQuantityInput!) { + updateCartItemsQuantity(input: $updateCartItemsQuantityInput) { + cart { + ${cartPayloadFragment} + } + } + } +` + +export default updateCartItemsQuantityMutation diff --git a/framework/reactioncommerce/utils/normalize.ts b/framework/reactioncommerce/utils/normalize.ts new file mode 100644 index 00000000..8aec1717 --- /dev/null +++ b/framework/reactioncommerce/utils/normalize.ts @@ -0,0 +1,294 @@ +import { + Product, + Customer, + ProductVariant, + ProductOption, + ProductOptionValues, +} from '@commerce/types' + +import { + Account, + Cart as ReactionCart, + CatalogProductVariant, + CartItemEdge, + CatalogItemProduct, + CatalogProduct, + ImageInfo, + CartItem, +} from '../schema' + +import type { Cart, LineItem } from '../types' + +const normalizeProductImages = (images: ImageInfo[], name: string) => + images.map((image) => ({ + url: image?.URLs?.original || image?.URLs?.medium || '', + alt: name, + })) + +const normalizeProductOption = (variant: CatalogProductVariant) => { + const option = <ProductOption>{ + __typename: 'MultipleChoiceOption', + id: variant._id, + displayName: variant.attributeLabel, + values: variant.optionTitle ? [{ label: variant.optionTitle }] : [], + } + option.values = option.values.map((value) => + colorizeProductOptionValue(value, option.displayName) + ) + + return option +} + +function colorizeProductOptionValue( + value: ProductOptionValues, + displayName: string +): ProductOptionValues { + if (displayName.toLowerCase() === 'color') { + value.hexColors = [value.label] + } + return value +} + +const normalizeProductVariants = ( + variants: Array<CatalogProductVariant> +): ProductVariant[] => { + return variants.reduce( + (productVariants: ProductVariant[], variant: CatalogProductVariant) => { + if (variantHasOptions(variant)) { + productVariants.push(...flatVariantOptions(variant)) + return productVariants + } + + const { sku, title, pricing = [], variantId } = variant ?? {} + const variantPrice = pricing[0]?.price ?? pricing[0]?.minPrice ?? 0 + + productVariants.push(<ProductVariant>{ + id: variantId ?? '', + name: title, + sku: sku ?? variantId, + price: variantPrice, + listPrice: pricing[0]?.compareAtPrice?.amount ?? variantPrice, + requiresShipping: true, + options: [normalizeProductOption(variant)], + }) + + return productVariants + }, + [] + ) +} + +function groupProductOptionsByAttributeLabel( + variants: CatalogProductVariant[] +): ProductOption[] { + return variants.reduce( + ( + groupedOptions: ProductOption[], + currentVariant: CatalogProductVariant + ) => { + groupedOptions = mergeVariantOptionsWithExistingOptions( + groupedOptions, + currentVariant + ) + + if (variantHasOptions(currentVariant)) { + (<CatalogProductVariant[]>currentVariant.options).forEach( + (variantOption) => { + groupedOptions = mergeVariantOptionsWithExistingOptions( + groupedOptions, + variantOption + ) + } + ) + } + + return groupedOptions + }, + [] + ) +} + +function mergeVariantOptionsWithExistingOptions( + groupedOptions: ProductOption[], + currentVariant: CatalogProductVariant +): ProductOption[] { + const matchingOptionIndex = findCurrentVariantOptionsInGroupedOptions( + groupedOptions, + currentVariant + ) + + return matchingOptionIndex !== -1 + ? mergeWithExistingOptions( + groupedOptions, + currentVariant, + matchingOptionIndex + ) + : addNewProductOption(groupedOptions, currentVariant) +} + +function findCurrentVariantOptionsInGroupedOptions( + groupedOptions: ProductOption[], + currentVariant: CatalogProductVariant +): number { + return groupedOptions.findIndex( + (option) => + option.displayName.toLowerCase() === + currentVariant.attributeLabel.toLowerCase() + ) +} + +function mergeWithExistingOptions( + groupedOptions: ProductOption[], + currentVariant: CatalogProductVariant, + matchingOptionIndex: number +) { + const currentVariantOption = normalizeProductOption(currentVariant) + groupedOptions[matchingOptionIndex].values = [ + ...groupedOptions[matchingOptionIndex].values, + ...currentVariantOption.values, + ] + + return groupedOptions +} + +function addNewProductOption( + groupedOptions: ProductOption[], + currentVariant: CatalogProductVariant +) { + return [...groupedOptions, normalizeProductOption(currentVariant)] +} + +export function normalizeProduct(productNode: CatalogItemProduct): Product { + const product = productNode.product + if (!product) { + return <Product>{} + } + + const { + _id, + productId, + title, + description, + slug, + sku, + media, + pricing, + variants, + } = <CatalogProduct>product + + return { + id: productId ?? _id, + name: title ?? '', + description: description ?? '', + slug: slug?.replace(/^\/+|\/+$/g, '') ?? '', + path: slug ?? '', + sku: sku ?? '', + images: media?.length + ? normalizeProductImages(<ImageInfo[]>media, title ?? '') + : [], + vendor: product.vendor, + price: { + value: pricing[0]?.minPrice ?? 0, + currencyCode: pricing[0]?.currency.code, + }, + variants: !!variants + ? normalizeProductVariants(<CatalogProductVariant[]>variants) + : [], + options: !!variants + ? groupProductOptionsByAttributeLabel(<CatalogProductVariant[]>variants) + : [], + } +} + +export function normalizeCart(cart: ReactionCart): Cart { + return { + id: cart._id, + customerId: '', + email: '', + createdAt: cart.createdAt, + currency: { + code: cart.checkout?.summary?.total?.currency.code ?? '', + }, + taxesIncluded: false, + lineItems: + cart.items?.edges?.map((cartItem) => + normalizeLineItem(<CartItemEdge>cartItem) + ) ?? [], + lineItemsSubtotalPrice: +(cart.checkout?.summary?.itemTotal?.amount ?? 0), + subtotalPrice: +(cart.checkout?.summary?.itemTotal?.amount ?? 0), + totalPrice: cart.checkout?.summary?.total?.amount ?? 0, + discounts: [], + } +} + +function normalizeLineItem(cartItemEdge: CartItemEdge): LineItem { + const cartItem = cartItemEdge.node + + if (!cartItem) { + return <LineItem>{} + } + + const { + _id, + compareAtPrice, + imageURLs, + title, + productConfiguration, + priceWhenAdded, + optionTitle, + variantTitle, + quantity, + } = <CartItem>cartItem + + return { + id: _id, + variantId: String(productConfiguration?.productVariantId), + productId: String(productConfiguration?.productId), + name: `${title}`, + quantity, + variant: { + id: String(productConfiguration?.productVariantId), + sku: String(productConfiguration?.productVariantId), + name: String(optionTitle || variantTitle), + image: { + url: imageURLs?.thumbnail ?? '/product-img-placeholder.svg', + }, + requiresShipping: true, + price: priceWhenAdded?.amount, + listPrice: compareAtPrice?.amount ?? 0, + options: [], + }, + path: '', + discounts: [], + options: [ + { + value: String(optionTitle || variantTitle), + }, + ], + } +} + +export function normalizeCustomer(viewer: Account): Customer { + if (!viewer) { + return <Customer>{} + } + + return <Customer>{ + firstName: viewer.firstName ?? '', + lastName: viewer.lastName ?? '', + email: viewer.primaryEmailAddress, + } +} + +function flatVariantOptions(variant: CatalogProductVariant): ProductVariant[] { + const variantOptions = <CatalogProductVariant[]>variant.options + + return normalizeProductVariants(variantOptions).map((variantOption) => { + variantOption.options.push(normalizeProductOption(variant)) + return variantOption + }) +} + +function variantHasOptions(variant: CatalogProductVariant) { + return !!variant.options && variant.options.length != 0 +} diff --git a/framework/reactioncommerce/utils/queries/account-cart-by-account-id.ts b/framework/reactioncommerce/utils/queries/account-cart-by-account-id.ts new file mode 100644 index 00000000..f8fcbab7 --- /dev/null +++ b/framework/reactioncommerce/utils/queries/account-cart-by-account-id.ts @@ -0,0 +1,11 @@ +import { cartQueryFragment } from '@framework/utils/queries/get-cart-query' + +const accountCartByAccountIdQuery = ` + query accountCartByAccountIdQuery($accountId: ID!, $shopId: ID!, $itemsAfterCursor: ConnectionCursor) { + cart: accountCartByAccountId(accountId: $accountId, shopId: $shopId) { + ${cartQueryFragment} + } + } +` + +export default accountCartByAccountIdQuery diff --git a/framework/reactioncommerce/utils/queries/catalog-items-query.ts b/framework/reactioncommerce/utils/queries/catalog-items-query.ts new file mode 100644 index 00000000..c906f0a5 --- /dev/null +++ b/framework/reactioncommerce/utils/queries/catalog-items-query.ts @@ -0,0 +1,69 @@ +export const catalogItemsConnection = ` +pageInfo { + hasNextPage + hasPreviousPage +} +edges { + node { + _id + ... on CatalogItemProduct { + product { + _id + title + slug + description + vendor + isLowQuantity + isSoldOut + isBackorder + shop { + currency { + code + } + } + pricing { + currency { + code + } + displayPrice + minPrice + maxPrice + } + media { + URLs { + thumbnail + small + medium + large + original + } + } + } + } + } +}` + +export const catalogItemsFragment = ` +catalogItems( + first: $first + sortBy: $sortBy + tagIds: $tagIds + shopIds: $shopIds + searchQuery: $searchQuery +) { + ${catalogItemsConnection} +} +` + +const catalogItemsQuery = /* GraphQL */ ` + query catalogItems( + $first: ConnectionLimitInt = 250 + $sortBy: CatalogItemSortByField = updatedAt + $tagIds: [ID] + $shopIds: [ID]! + $searchQuery: String + ) { + ${catalogItemsFragment} + } +` +export default catalogItemsQuery diff --git a/framework/reactioncommerce/utils/queries/get-all-collections-query.ts b/framework/reactioncommerce/utils/queries/get-all-collections-query.ts new file mode 100644 index 00000000..6644df42 --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-all-collections-query.ts @@ -0,0 +1,14 @@ +const getTagsQuery = /* GraphQL */ ` + query getTags($first: ConnectionLimitInt!, $shopId: ID!) { + tags(first: $first, shopId: $shopId) { + edges { + node { + _id + displayTitle + slug + } + } + } + } +` +export default getTagsQuery diff --git a/framework/reactioncommerce/utils/queries/get-all-pages-query.ts b/framework/reactioncommerce/utils/queries/get-all-pages-query.ts new file mode 100644 index 00000000..83853563 --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-all-pages-query.ts @@ -0,0 +1,21 @@ +export const getAllPagesQuery = /* GraphQL */ ` + query getAllPages($shopId: ID!, $language: String! = "en") { + shop(id: $shopId) { + defaultNavigationTree(language: $language) { + items { + navigationItem { + _id + data { + contentForLanguage + classNames + url + isUrlRelative + shouldOpenInNewWindow + } + } + } + } + } + } +` +export default getAllPagesQuery diff --git a/framework/reactioncommerce/utils/queries/get-all-product-vendors-query.ts b/framework/reactioncommerce/utils/queries/get-all-product-vendors-query.ts new file mode 100644 index 00000000..ab55b4ea --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-all-product-vendors-query.ts @@ -0,0 +1,10 @@ +const getAllProductVendors = /* GraphQL */ ` + query getAllProductVendors($shopIds: [ID]!) { + vendors(shopIds: $shopIds) { + nodes { + name + } + } + } +` +export default getAllProductVendors diff --git a/framework/reactioncommerce/utils/queries/get-all-products-paths-query.ts b/framework/reactioncommerce/utils/queries/get-all-products-paths-query.ts new file mode 100644 index 00000000..7a3df349 --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-all-products-paths-query.ts @@ -0,0 +1,25 @@ +const getAllProductsPathsQuery = /* GraphQL */ ` + query catalogItems( + $first: ConnectionLimitInt = 250 + $sortBy: CatalogItemSortByField = updatedAt + $shopIds: [ID]! + ) { + catalogItems(first: $first, sortBy: $sortBy, shopIds: $shopIds) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + ... on CatalogItemProduct { + product { + slug + } + } + } + cursor + } + } + } +` +export default getAllProductsPathsQuery diff --git a/framework/reactioncommerce/utils/queries/get-anonymous-cart.ts b/framework/reactioncommerce/utils/queries/get-anonymous-cart.ts new file mode 100644 index 00000000..dc2c433c --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-anonymous-cart.ts @@ -0,0 +1,11 @@ +import { cartQueryFragment } from './get-cart-query' + +export const getAnomymousCart = ` + query anonymousCartByCartIdQuery($cartId: ID!, $cartToken: String!, $itemsAfterCursor: ConnectionCursor) { + cart: anonymousCartByCartId(cartId: $cartId, cartToken: $cartToken) { + ${cartQueryFragment} + } + } +` + +export default getAnomymousCart diff --git a/framework/reactioncommerce/utils/queries/get-cart-query.ts b/framework/reactioncommerce/utils/queries/get-cart-query.ts new file mode 100644 index 00000000..bae98d0b --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-cart-query.ts @@ -0,0 +1,241 @@ +export const cartCommon = ` + _id + createdAt + account { + _id + emailRecords { + address + } + } + shop { + _id + currency { + code + } + } + email + updatedAt + expiresAt + checkout { + fulfillmentGroups { + _id + type + data { + shippingAddress { + address1 + address2 + city + company + country + fullName + isBillingDefault + isCommercial + isShippingDefault + phone + postal + region + } + } + availableFulfillmentOptions { + price { + amount + displayAmount + } + fulfillmentMethod { + _id + name + displayName + } + } + selectedFulfillmentOption { + fulfillmentMethod { + _id + name + displayName + } + price { + amount + displayAmount + } + handlingPrice { + amount + displayAmount + } + } + shop { + _id + } + shippingAddress { + address1 + address2 + city + company + country + fullName + isBillingDefault + isCommercial + isShippingDefault + phone + postal + region + } + } + summary { + fulfillmentTotal { + displayAmount + } + itemTotal { + amount + displayAmount + } + surchargeTotal { + amount + displayAmount + } + taxTotal { + amount + displayAmount + } + total { + amount + currency { + code + } + displayAmount + } + } + } + totalItemQuantity +` + +const cartItemConnectionFragment = ` + pageInfo { + hasNextPage + endCursor + } + edges { + node { + _id + productConfiguration { + productId + productVariantId + } + addedAt + attributes { + label + value + } + createdAt + isBackorder + isLowQuantity + isSoldOut + imageURLs { + large + small + original + medium + thumbnail + } + metafields { + value + key + } + parcel { + length + width + weight + height + } + price { + amount + displayAmount + currency { + code + } + } + priceWhenAdded { + amount + displayAmount + currency { + code + } + } + productSlug + productType + quantity + shop { + _id + } + subtotal { + displayAmount + } + title + productTags { + nodes { + name + } + } + productVendor + variantTitle + optionTitle + updatedAt + inventoryAvailableToSell + } + } +` + +export const cartPayloadFragment = ` + ${cartCommon} + items { + ${cartItemConnectionFragment} + } +` + +export const incorrectPriceFailureDetailsFragment = ` + currentPrice { + amount + currency { + code + } + displayAmount + } + productConfiguration { + productId + productVariantId + } + providedPrice { + amount + currency { + code + } + displayAmount + } +` + +export const minOrderQuantityFailureDetailsFragment = ` + minOrderQuantity + productConfiguration { + productId + productVariantId + } + quantity +` + +const getCartQuery = /* GraphQL */ ` + query($checkoutId: ID!) { + node(id: $checkoutId) { + ... on Checkout { + ${cartCommon} + } + } + } +` + +export const cartQueryFragment = ` + ${cartCommon} + items(first: 20, after: $itemsAfterCursor) { + ${cartItemConnectionFragment} + } +` + +export default getCartQuery diff --git a/framework/reactioncommerce/utils/queries/get-collection-products-query.ts b/framework/reactioncommerce/utils/queries/get-collection-products-query.ts new file mode 100644 index 00000000..4c5ea3dc --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-collection-products-query.ts @@ -0,0 +1,24 @@ +import { catalogItemsConnection } from './catalog-items-query' + +const getCollectionProductsQuery = /* GraphQL */ ` + query getProductsFromCollection( + $categoryId: ID! + $first: Int = 250 + $sortKey: ProductCollectionSortKeys = RELEVANCE + $reverse: Boolean = false + ) { + node(id: $categoryId) { + id + ... on Collection { + products( + first: $first + sortKey: $sortKey + reverse: $reverse + ) { + ${catalogItemsConnection} + } + } + } + } +` +export default getCollectionProductsQuery diff --git a/framework/reactioncommerce/utils/queries/get-page-query.ts b/framework/reactioncommerce/utils/queries/get-page-query.ts new file mode 100644 index 00000000..2ca79abd --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-page-query.ts @@ -0,0 +1,14 @@ +export const getPageQuery = /* GraphQL */ ` + query($id: ID!) { + node(id: $id) { + id + ... on Page { + title + handle + body + bodySummary + } + } + } +` +export default getPageQuery diff --git a/framework/reactioncommerce/utils/queries/get-product-query.ts b/framework/reactioncommerce/utils/queries/get-product-query.ts new file mode 100644 index 00000000..6b72be61 --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-product-query.ts @@ -0,0 +1,181 @@ +const getProductQuery = /* GraphQL */ ` + query getProductBySlug($slug: String!) { + catalogItemProduct(slugOrId: $slug) { + product { + _id + productId + title + slug + description + vendor + isLowQuantity + isSoldOut + isBackorder + metafields { + description + key + namespace + scope + value + valueType + } + pricing { + currency { + code + } + displayPrice + minPrice + maxPrice + } + shop { + currency { + code + } + } + primaryImage { + URLs { + large + medium + original + small + thumbnail + } + priority + productId + variantId + } + media { + priority + productId + variantId + URLs { + thumbnail + small + medium + large + original + } + } + tags { + nodes { + name + slug + position + } + } + variants { + _id + variantId + attributeLabel + title + optionTitle + index + pricing { + compareAtPrice { + displayAmount + } + price + currency { + code + } + displayPrice + } + canBackorder + inventoryAvailableToSell + isBackorder + isSoldOut + isLowQuantity + options { + _id + variantId + attributeLabel + title + index + pricing { + compareAtPrice { + displayAmount + } + price + currency { + code + } + displayPrice + } + optionTitle + canBackorder + inventoryAvailableToSell + isBackorder + isSoldOut + isLowQuantity + media { + priority + productId + variantId + URLs { + thumbnail + small + medium + large + original + } + } + metafields { + description + key + namespace + scope + value + valueType + } + primaryImage { + URLs { + large + medium + original + small + thumbnail + } + priority + productId + variantId + } + } + media { + priority + productId + variantId + URLs { + thumbnail + small + medium + large + original + } + } + metafields { + description + key + namespace + scope + value + valueType + } + primaryImage { + URLs { + large + medium + original + small + thumbnail + } + priority + productId + variantId + } + } + } + } + } +` + +export default getProductQuery diff --git a/framework/reactioncommerce/utils/queries/get-viewer-id-query.ts b/framework/reactioncommerce/utils/queries/get-viewer-id-query.ts new file mode 100644 index 00000000..9940dd0e --- /dev/null +++ b/framework/reactioncommerce/utils/queries/get-viewer-id-query.ts @@ -0,0 +1,8 @@ +export const viewerIdQuery = /* GraphQL */ ` + query viewer { + viewer { + _id + } + } +` +export default viewerIdQuery diff --git a/framework/reactioncommerce/utils/queries/index.ts b/framework/reactioncommerce/utils/queries/index.ts new file mode 100644 index 00000000..a484027e --- /dev/null +++ b/framework/reactioncommerce/utils/queries/index.ts @@ -0,0 +1,10 @@ +export { default as getTagsQuery } from './get-all-collections-query' +export { default as getProductQuery } from './get-product-query' +export { default as catalogItemsQuery } from './catalog-items-query' +export { default as getAllProductsPathtsQuery } from './get-all-products-paths-query' +export { default as getAllProductVendors } from './get-all-product-vendors-query' +export { default as getCollectionProductsQuery } from './get-collection-products-query' +export { default as getCartQuery } from './get-cart-query' +export { default as getAllPagesQuery } from './get-all-pages-query' +export { default as getPageQuery } from './get-page-query' +export { default as viewerQuery } from './viewer-query' diff --git a/framework/reactioncommerce/utils/queries/viewer-query.ts b/framework/reactioncommerce/utils/queries/viewer-query.ts new file mode 100644 index 00000000..fa08ba0e --- /dev/null +++ b/framework/reactioncommerce/utils/queries/viewer-query.ts @@ -0,0 +1,26 @@ +export const viewerQuery = /* GraphQL */ ` + query viewer { + viewer { + _id + addressBook { + edges { + node { + _id + isBillingDefault + isShippingDefault + phone + } + } + } + emailRecords { + address + } + firstName + lastName + name + primaryEmailAddress + createdAt + } + } +` +export default viewerQuery diff --git a/framework/reactioncommerce/wishlist/use-add-item.tsx b/framework/reactioncommerce/wishlist/use-add-item.tsx new file mode 100644 index 00000000..75f067c3 --- /dev/null +++ b/framework/reactioncommerce/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/framework/reactioncommerce/wishlist/use-remove-item.tsx b/framework/reactioncommerce/wishlist/use-remove-item.tsx new file mode 100644 index 00000000..a2d3a8a0 --- /dev/null +++ b/framework/reactioncommerce/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/framework/reactioncommerce/wishlist/use-wishlist.tsx b/framework/reactioncommerce/wishlist/use-wishlist.tsx new file mode 100644 index 00000000..56c5a49c --- /dev/null +++ b/framework/reactioncommerce/wishlist/use-wishlist.tsx @@ -0,0 +1,46 @@ +// TODO: replace this hook and other wishlist hooks with a handler, or remove them if +// Reaction Commerce doesn't have a wishlist + +import { HookFetcher } from '@commerce/utils/types' +import { Product } from '../schema' + +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<Wishlist | null, UseWishlistInput> = () => { + return null +} + +export function extendHook( + customFetcher: typeof fetcher, + // swrOptions?: SwrOptions<Wishlist | null, UseWishlistInput> + swrOptions?: any +) { + const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => { + return { data: null } + } + + useWishlist.extend = extendHook + + return useWishlist +} + +export default extendHook(fetcher) diff --git a/framework/shopify/.env.template b/framework/shopify/.env.template new file mode 100644 index 00000000..74f44683 --- /dev/null +++ b/framework/shopify/.env.template @@ -0,0 +1,4 @@ +COMMERCE_PROVIDER=shopify + +NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN= +NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN= diff --git a/framework/shopify/README.md b/framework/shopify/README.md new file mode 100644 index 00000000..d67111a4 --- /dev/null +++ b/framework/shopify/README.md @@ -0,0 +1,123 @@ +## Shopify Provider + +**Demo:** https://shopify.demo.vercel.store/ + +Before getting starter, a [Shopify](https://www.shopify.com/) account and store is required before using the provider. + +Next, copy the `.env.template` file in this directory to `.env.local` in the main directory (which will be ignored by Git): + +```bash +cp framework/shopify/.env.template .env.local +``` + +Then, set the environment variables in `.env.local` to match the ones from your store. + +## Contribute + +Our commitment to Open Source can be found [here](https://vercel.com/oss). + +If you find an issue with the provider or want a new feature, feel free to open a PR or [create a new issue](https://github.com/vercel/commerce/issues). + +## Modifications + +These modifications are temporarily until contributions are made to remove them. + +### Adding item to Cart + +```js +// components/product/ProductView/ProductView.tsx +const ProductView: FC<Props> = ({ product }) => { + const addToCart = async () => { + setLoading(true) + try { + await addItem({ + productId: product.id, + variantId: variant ? variant.id : product.variants[0].id, + }) + openSidebar() + setLoading(false) + } catch (err) { + setLoading(false) + } + } +} +``` + +### Proceed to Checkout + +```js +// components/cart/CartSidebarView/CartSidebarView.tsx +import { useCommerce } from '@framework' + +const CartSidebarView: FC = () => { + const { checkout } = useCommerce() + return ( + <Button href={checkout.webUrl} Component="a" width="100%"> + Proceed to Checkout + </Button> + ) +} +``` + +## APIs + +Collections of APIs to fetch data from a Shopify store. + +The data is fetched using the [Shopify JavaScript Buy SDK](https://github.com/Shopify/js-buy-sdk#readme). Read the [Shopify Storefront API reference](https://shopify.dev/docs/storefront-api/reference) for more information. + +### getProduct + +Get a single product by its `handle`. + +```js +import getProduct from '@framework/product/get-product' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const product = await getProduct({ + variables: { slug }, + config, +}) +``` + +### getAllProducts + +```js +import getAllProducts from '@framework/product/get-all-products' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const { products } = await getAllProducts({ + variables: { first: 12 }, + config, +}) +``` + +### getAllCollections + +```js +import getAllCollections from '@framework/product/get-all-collections' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const collections = await getAllCollections({ + config, +}) +``` + +### getAllPages + +```js +import getAllPages from '@framework/common/get-all-pages' +import { getConfig } from '@framework/api' + +const config = getConfig() + +const pages = await getAllPages({ + variables: { first: 12 }, + config, +}) +``` diff --git a/framework/shopify/api/cart/index.ts b/framework/shopify/api/cart/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/shopify/api/cart/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/catalog/index.ts b/framework/shopify/api/catalog/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/shopify/api/catalog/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/catalog/products.ts b/framework/shopify/api/catalog/products.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/shopify/api/catalog/products.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/checkout/index.ts b/framework/shopify/api/checkout/index.ts new file mode 100644 index 00000000..24407846 --- /dev/null +++ b/framework/shopify/api/checkout/index.ts @@ -0,0 +1,46 @@ +import isAllowedMethod from '../utils/is-allowed-method' +import createApiHandler, { + ShopifyApiHandler, +} from '../utils/create-api-handler' + +import { + SHOPIFY_CHECKOUT_ID_COOKIE, + SHOPIFY_CHECKOUT_URL_COOKIE, + SHOPIFY_CUSTOMER_TOKEN_COOKIE, +} from '../../const' + +import { getConfig } from '..' +import associateCustomerWithCheckoutMutation from '../../utils/mutations/associate-customer-with-checkout' + +const METHODS = ['GET'] + +const checkoutApi: ShopifyApiHandler<any> = async (req, res, config) => { + if (!isAllowedMethod(req, res, METHODS)) return + + config = getConfig() + + const { cookies } = req + const checkoutUrl = cookies[SHOPIFY_CHECKOUT_URL_COOKIE] + const customerCookie = cookies[SHOPIFY_CUSTOMER_TOKEN_COOKIE] + + if (customerCookie) { + try { + await config.fetch(associateCustomerWithCheckoutMutation, { + variables: { + checkoutId: cookies[SHOPIFY_CHECKOUT_ID_COOKIE], + customerAccessToken: cookies[SHOPIFY_CUSTOMER_TOKEN_COOKIE], + }, + }) + } catch (error) { + console.error(error) + } + } + + if (checkoutUrl) { + res.redirect(checkoutUrl) + } else { + res.redirect('/cart') + } +} + +export default createApiHandler(checkoutApi, {}, {}) diff --git a/framework/shopify/api/customer.ts b/framework/shopify/api/customer.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/shopify/api/customer.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/customers/index.ts b/framework/shopify/api/customers/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/shopify/api/customers/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/customers/login.ts b/framework/shopify/api/customers/login.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/shopify/api/customers/login.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/customers/logout.ts b/framework/shopify/api/customers/logout.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/shopify/api/customers/logout.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/customers/signup.ts b/framework/shopify/api/customers/signup.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/shopify/api/customers/signup.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/shopify/api/index.ts b/framework/shopify/api/index.ts new file mode 100644 index 00000000..387ed02f --- /dev/null +++ b/framework/shopify/api/index.ts @@ -0,0 +1,61 @@ +import type { CommerceAPIConfig } from '@commerce/api' + +import { + API_URL, + API_TOKEN, + SHOPIFY_CHECKOUT_ID_COOKIE, + SHOPIFY_CUSTOMER_TOKEN_COOKIE, +} from '../const' + +if (!API_URL) { + throw new Error( + `The environment variable NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN is missing and it's required to access your store` + ) +} + +if (!API_TOKEN) { + throw new Error( + `The environment variable NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN is missing and it's required to access your store` + ) +} + +import fetchGraphqlApi from './utils/fetch-graphql-api' + +export interface ShopifyConfig extends CommerceAPIConfig {} + +export class Config { + private config: ShopifyConfig + + constructor(config: ShopifyConfig) { + this.config = config + } + + getConfig(userConfig: Partial<ShopifyConfig> = {}) { + return Object.entries(userConfig).reduce<ShopifyConfig>( + (cfg, [key, value]) => Object.assign(cfg, { [key]: value }), + { ...this.config } + ) + } + + setConfig(newConfig: Partial<ShopifyConfig>) { + Object.assign(this.config, newConfig) + } +} + +const config = new Config({ + locale: 'en-US', + commerceUrl: API_URL, + apiToken: API_TOKEN!, + cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, + cartCookieMaxAge: 60 * 60 * 24 * 30, + fetch: fetchGraphqlApi, + customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE, +}) + +export function getConfig(userConfig?: Partial<ShopifyConfig>) { + return config.getConfig(userConfig) +} + +export function setConfig(newConfig: Partial<ShopifyConfig>) { + return config.setConfig(newConfig) +} diff --git a/framework/shopify/api/utils/create-api-handler.ts b/framework/shopify/api/utils/create-api-handler.ts new file mode 100644 index 00000000..8820aeab --- /dev/null +++ b/framework/shopify/api/utils/create-api-handler.ts @@ -0,0 +1,58 @@ +import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next' +import { ShopifyConfig, getConfig } from '..' + +export type ShopifyApiHandler< + T = any, + H extends ShopifyHandlers = {}, + Options extends {} = {} +> = ( + req: NextApiRequest, + res: NextApiResponse<ShopifyApiResponse<T>>, + config: ShopifyConfig, + handlers: H, + // Custom configs that may be used by a particular handler + options: Options +) => void | Promise<void> + +export type ShopifyHandler<T = any, Body = null> = (options: { + req: NextApiRequest + res: NextApiResponse<ShopifyApiResponse<T>> + config: ShopifyConfig + body: Body +}) => void | Promise<void> + +export type ShopifyHandlers<T = any> = { + [k: string]: ShopifyHandler<T, any> +} + +export type ShopifyApiResponse<T> = { + data: T | null + errors?: { message: string; code?: string }[] +} + +export default function createApiHandler< + T = any, + H extends ShopifyHandlers = {}, + Options extends {} = {} +>( + handler: ShopifyApiHandler<T, H, Options>, + handlers: H, + defaultOptions: Options +) { + return function getApiHandler({ + config, + operations, + options, + }: { + config?: ShopifyConfig + operations?: Partial<H> + options?: Options extends {} ? Partial<Options> : never + } = {}): NextApiHandler { + const ops = { ...operations, ...handlers } + const opts = { ...defaultOptions, ...options } + + return function apiHandler(req, res) { + return handler(req, res, getConfig(config), ops, opts) + } + } +} diff --git a/framework/shopify/api/utils/fetch-all-products.ts b/framework/shopify/api/utils/fetch-all-products.ts new file mode 100644 index 00000000..9fa70a5e --- /dev/null +++ b/framework/shopify/api/utils/fetch-all-products.ts @@ -0,0 +1,41 @@ +import { ProductEdge } from '../../schema' +import { ShopifyConfig } from '..' + +const fetchAllProducts = async ({ + config, + query, + variables, + acc = [], + cursor, +}: { + config: ShopifyConfig + query: string + acc?: ProductEdge[] + variables?: any + cursor?: string +}): Promise<ProductEdge[]> => { + const { data } = await config.fetch(query, { + variables: { ...variables, cursor }, + }) + + const edges: ProductEdge[] = data.products?.edges ?? [] + const hasNextPage = data.products?.pageInfo?.hasNextPage + acc = acc.concat(edges) + + if (hasNextPage) { + const cursor = edges.pop()?.cursor + if (cursor) { + return fetchAllProducts({ + config, + query, + variables, + acc, + cursor, + }) + } + } + + return acc +} + +export default fetchAllProducts diff --git a/framework/shopify/api/utils/fetch-graphql-api.ts b/framework/shopify/api/utils/fetch-graphql-api.ts new file mode 100644 index 00000000..321cba2a --- /dev/null +++ b/framework/shopify/api/utils/fetch-graphql-api.ts @@ -0,0 +1,34 @@ +import type { GraphQLFetcher } from '@commerce/api' +import fetch from './fetch' + +import { API_URL, API_TOKEN } from '../../const' +import { getError } from '../../utils/handle-fetch-response' + +const fetchGraphqlApi: GraphQLFetcher = async ( + query: string, + { variables } = {}, + fetchOptions +) => { + const res = await fetch(API_URL, { + ...fetchOptions, + method: 'POST', + headers: { + 'X-Shopify-Storefront-Access-Token': API_TOKEN!, + ...fetchOptions?.headers, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query, + variables, + }), + }) + + const { data, errors, status } = await res.json() + + if (errors) { + throw getError(errors, status) + } + + return { data, res } +} +export default fetchGraphqlApi diff --git a/framework/shopify/api/utils/fetch.ts b/framework/shopify/api/utils/fetch.ts new file mode 100644 index 00000000..0b836710 --- /dev/null +++ b/framework/shopify/api/utils/fetch.ts @@ -0,0 +1,2 @@ +import zeitFetch from '@vercel/fetch' +export default zeitFetch() diff --git a/framework/shopify/api/utils/is-allowed-method.ts b/framework/shopify/api/utils/is-allowed-method.ts new file mode 100644 index 00000000..78bbba56 --- /dev/null +++ b/framework/shopify/api/utils/is-allowed-method.ts @@ -0,0 +1,28 @@ +import type { NextApiRequest, NextApiResponse } from 'next' + +export default function isAllowedMethod( + req: NextApiRequest, + res: NextApiResponse, + allowedMethods: string[] +) { + const methods = allowedMethods.includes('OPTIONS') + ? allowedMethods + : [...allowedMethods, 'OPTIONS'] + + if (!req.method || !methods.includes(req.method)) { + res.status(405) + res.setHeader('Allow', methods.join(', ')) + res.end() + return false + } + + if (req.method === 'OPTIONS') { + res.status(200) + res.setHeader('Allow', methods.join(', ')) + res.setHeader('Content-Length', '0') + res.end() + return false + } + + return true +} diff --git a/framework/shopify/api/wishlist/index.tsx b/framework/shopify/api/wishlist/index.tsx new file mode 100644 index 00000000..a7285667 --- /dev/null +++ b/framework/shopify/api/wishlist/index.tsx @@ -0,0 +1,2 @@ +export type WishlistItem = { product: any; id: number } +export default function () {} diff --git a/framework/shopify/auth/use-login.tsx b/framework/shopify/auth/use-login.tsx new file mode 100644 index 00000000..7993822c --- /dev/null +++ b/framework/shopify/auth/use-login.tsx @@ -0,0 +1,71 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError, ValidationError } from '@commerce/utils/errors' +import useCustomer from '../customer/use-customer' +import createCustomerAccessTokenMutation from '../utils/mutations/customer-access-token-create' +import { + CustomerAccessTokenCreateInput, + CustomerUserError, + Mutation, + MutationCheckoutCreateArgs, +} from '../schema' +import useLogin, { UseLogin } from '@commerce/auth/use-login' +import { setCustomerToken, throwUserErrors } from '../utils' + +export default useLogin as UseLogin<typeof handler> + +const getErrorMessage = ({ code, message }: CustomerUserError) => { + switch (code) { + case 'UNIDENTIFIED_CUSTOMER': + message = 'Cannot find an account that matches the provided credentials' + break + } + return message +} + +export const handler: MutationHook<null, {}, CustomerAccessTokenCreateInput> = { + fetchOptions: { + query: createCustomerAccessTokenMutation, + }, + async fetcher({ input: { email, password }, options, fetch }) { + if (!(email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to login', + }) + } + + const { customerAccessTokenCreate } = await fetch< + Mutation, + MutationCheckoutCreateArgs + >({ + ...options, + variables: { + input: { email, password }, + }, + }) + + throwUserErrors(customerAccessTokenCreate?.customerUserErrors) + + const customerAccessToken = customerAccessTokenCreate?.customerAccessToken + const accessToken = customerAccessToken?.accessToken + + if (accessToken) { + setCustomerToken(accessToken) + } + + return null + }, + useHook: ({ fetch }) => () => { + const { revalidate } = useCustomer() + + return useCallback( + async function login(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/shopify/auth/use-logout.tsx b/framework/shopify/auth/use-logout.tsx new file mode 100644 index 00000000..81a3b8cd --- /dev/null +++ b/framework/shopify/auth/use-logout.tsx @@ -0,0 +1,36 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import useLogout, { UseLogout } from '@commerce/auth/use-logout' +import useCustomer from '../customer/use-customer' +import customerAccessTokenDeleteMutation from '../utils/mutations/customer-access-token-delete' +import { getCustomerToken, setCustomerToken } from '../utils/customer-token' + +export default useLogout as UseLogout<typeof handler> + +export const handler: MutationHook<null> = { + fetchOptions: { + query: customerAccessTokenDeleteMutation, + }, + async fetcher({ options, fetch }) { + await fetch({ + ...options, + variables: { + customerAccessToken: getCustomerToken(), + }, + }) + setCustomerToken(null) + return null + }, + useHook: ({ fetch }) => () => { + const { mutate } = useCustomer() + + return useCallback( + async function logout() { + const data = await fetch() + await mutate(null, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/shopify/auth/use-signup.tsx b/framework/shopify/auth/use-signup.tsx new file mode 100644 index 00000000..9ca5c682 --- /dev/null +++ b/framework/shopify/auth/use-signup.tsx @@ -0,0 +1,70 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError, ValidationError } from '@commerce/utils/errors' +import useSignup, { UseSignup } from '@commerce/auth/use-signup' +import useCustomer from '../customer/use-customer' +import { + CustomerCreateInput, + Mutation, + MutationCustomerCreateArgs, +} from '../schema' + +import { customerCreateMutation } from '../utils/mutations' +import { handleAutomaticLogin, throwUserErrors } from '../utils' + +export default useSignup as UseSignup<typeof handler> + +export const handler: MutationHook< + null, + {}, + CustomerCreateInput, + CustomerCreateInput +> = { + fetchOptions: { + query: customerCreateMutation, + }, + async fetcher({ + input: { firstName, lastName, email, password }, + options, + fetch, + }) { + if (!(firstName && lastName && email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to signup', + }) + } + + const { customerCreate } = await fetch< + Mutation, + MutationCustomerCreateArgs + >({ + ...options, + variables: { + input: { + firstName, + lastName, + email, + password, + }, + }, + }) + + throwUserErrors(customerCreate?.customerUserErrors) + await handleAutomaticLogin(fetch, { email, password }) + + return null + }, + useHook: ({ fetch }) => () => { + const { revalidate } = useCustomer() + + return useCallback( + async function signup(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/shopify/cart/index.ts b/framework/shopify/cart/index.ts new file mode 100644 index 00000000..f6d36b44 --- /dev/null +++ b/framework/shopify/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 useUpdateItem } from './use-update-item' +export { default as useRemoveItem } from './use-remove-item' diff --git a/framework/shopify/cart/use-add-item.tsx b/framework/shopify/cart/use-add-item.tsx new file mode 100644 index 00000000..cce0950e --- /dev/null +++ b/framework/shopify/cart/use-add-item.tsx @@ -0,0 +1,60 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' +import useCart from './use-cart' +import { + checkoutLineItemAddMutation, + getCheckoutId, + checkoutToCart, +} from '../utils' +import { Cart, CartItemBody } from '../types' +import { Mutation, MutationCheckoutLineItemsAddArgs } from '../schema' + +export default useAddItem as UseAddItem<typeof handler> + +export const handler: MutationHook<Cart, {}, CartItemBody> = { + fetchOptions: { + query: checkoutLineItemAddMutation, + }, + async fetcher({ input: item, options, fetch }) { + if ( + item.quantity && + (!Number.isInteger(item.quantity) || item.quantity! < 1) + ) { + throw new CommerceError({ + message: 'The item quantity has to be a valid integer greater than 0', + }) + } + + const { checkoutLineItemsAdd } = await fetch< + Mutation, + MutationCheckoutLineItemsAddArgs + >({ + ...options, + variables: { + checkoutId: getCheckoutId(), + lineItems: [ + { + variantId: item.variantId, + quantity: item.quantity ?? 1, + }, + ], + }, + }) + + return checkoutToCart(checkoutLineItemsAdd) + }, + useHook: ({ fetch }) => () => { + const { mutate } = useCart() + + return useCallback( + async function addItem(input) { + const data = await fetch({ input }) + await mutate(data, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/shopify/cart/use-cart.tsx b/framework/shopify/cart/use-cart.tsx new file mode 100644 index 00000000..5f77360b --- /dev/null +++ b/framework/shopify/cart/use-cart.tsx @@ -0,0 +1,59 @@ +import { useMemo } from 'react' +import useCommerceCart, { + FetchCartInput, + UseCart, +} from '@commerce/cart/use-cart' + +import { Cart } from '../types' +import { SWRHook } from '@commerce/utils/types' +import { checkoutCreate, checkoutToCart } from '../utils' +import getCheckoutQuery from '../utils/queries/get-checkout-query' + +export default useCommerceCart as UseCart<typeof handler> + +export const handler: SWRHook< + Cart | null, + {}, + FetchCartInput, + { isEmpty?: boolean } +> = { + fetchOptions: { + query: getCheckoutQuery, + }, + async fetcher({ input: { cartId: checkoutId }, options, fetch }) { + let checkout + + if (checkoutId) { + const data = await fetch({ + ...options, + variables: { + checkoutId: checkoutId, + }, + }) + checkout = data.node + } + + if (checkout?.completedAt || !checkoutId) { + checkout = await checkoutCreate(fetch) + } + + return checkoutToCart({ checkout }) + }, + useHook: ({ useData }) => (input) => { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, + }) + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} diff --git a/framework/shopify/cart/use-remove-item.tsx b/framework/shopify/cart/use-remove-item.tsx new file mode 100644 index 00000000..8db38eac --- /dev/null +++ b/framework/shopify/cart/use-remove-item.tsx @@ -0,0 +1,71 @@ +import { useCallback } from 'react' +import type { + MutationHookContext, + HookFetcherContext, +} from '@commerce/utils/types' +import { RemoveCartItemBody } from '@commerce/types' +import { ValidationError } from '@commerce/utils/errors' +import useRemoveItem, { + RemoveItemInput as RemoveItemInputBase, + UseRemoveItem, +} from '@commerce/cart/use-remove-item' +import useCart from './use-cart' +import { + checkoutLineItemRemoveMutation, + getCheckoutId, + checkoutToCart, +} from '../utils' +import { Cart, LineItem } from '../types' +import { Mutation, MutationCheckoutLineItemsRemoveArgs } from '../schema' + +export type RemoveItemFn<T = any> = T extends LineItem + ? (input?: RemoveItemInput<T>) => Promise<Cart | null> + : (input: RemoveItemInput<T>) => Promise<Cart | null> + +export type RemoveItemInput<T = any> = T extends LineItem + ? Partial<RemoveItemInputBase> + : RemoveItemInputBase + +export default useRemoveItem as UseRemoveItem<typeof handler> + +export const handler = { + fetchOptions: { + query: checkoutLineItemRemoveMutation, + }, + async fetcher({ + input: { itemId }, + options, + fetch, + }: HookFetcherContext<RemoveCartItemBody>) { + const data = await fetch<Mutation, MutationCheckoutLineItemsRemoveArgs>({ + ...options, + variables: { checkoutId: getCheckoutId(), lineItemIds: [itemId] }, + }) + return checkoutToCart(data.checkoutLineItemsRemove) + }, + useHook: ({ + fetch, + }: MutationHookContext<Cart | null, RemoveCartItemBody>) => < + T extends LineItem | undefined = undefined + >( + ctx: { item?: T } = {} + ) => { + const { item } = ctx + const { mutate } = useCart() + const removeItem: RemoveItemFn<LineItem> = async (input) => { + const itemId = input?.id ?? item?.id + + if (!itemId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ input: { itemId } }) + await mutate(data, false) + return data + } + + return useCallback(removeItem as RemoveItemFn<T>, [fetch, mutate]) + }, +} diff --git a/framework/shopify/cart/use-update-item.tsx b/framework/shopify/cart/use-update-item.tsx new file mode 100644 index 00000000..49dd6be1 --- /dev/null +++ b/framework/shopify/cart/use-update-item.tsx @@ -0,0 +1,107 @@ +import { useCallback } from 'react' +import debounce from 'lodash.debounce' +import type { + HookFetcherContext, + MutationHookContext, +} from '@commerce/utils/types' +import { ValidationError } from '@commerce/utils/errors' +import useUpdateItem, { + UpdateItemInput as UpdateItemInputBase, + UseUpdateItem, +} from '@commerce/cart/use-update-item' + +import useCart from './use-cart' +import { handler as removeItemHandler } from './use-remove-item' +import type { Cart, LineItem, UpdateCartItemBody } from '../types' +import { checkoutToCart } from '../utils' +import { getCheckoutId, checkoutLineItemUpdateMutation } from '../utils' +import { Mutation, MutationCheckoutLineItemsUpdateArgs } from '../schema' + +export type UpdateItemInput<T = any> = T extends LineItem + ? Partial<UpdateItemInputBase<LineItem>> + : UpdateItemInputBase<LineItem> + +export default useUpdateItem as UseUpdateItem<typeof handler> + +export const handler = { + fetchOptions: { + query: checkoutLineItemUpdateMutation, + }, + async fetcher({ + input: { itemId, item }, + options, + fetch, + }: HookFetcherContext<UpdateCartItemBody>) { + if (Number.isInteger(item.quantity)) { + // Also allow the update hook to remove an item if the quantity is lower than 1 + if (item.quantity! < 1) { + return removeItemHandler.fetcher({ + options: removeItemHandler.fetchOptions, + input: { itemId }, + fetch, + }) + } + } else if (item.quantity) { + throw new ValidationError({ + message: 'The item quantity has to be a valid integer', + }) + } + const { checkoutLineItemsUpdate } = await fetch< + Mutation, + MutationCheckoutLineItemsUpdateArgs + >({ + ...options, + variables: { + checkoutId: getCheckoutId(), + lineItems: [ + { + id: itemId, + quantity: item.quantity, + }, + ], + }, + }) + + return checkoutToCart(checkoutLineItemsUpdate) + }, + useHook: ({ + fetch, + }: MutationHookContext<Cart | null, UpdateCartItemBody>) => < + T extends LineItem | undefined = undefined + >( + ctx: { + item?: T + wait?: number + } = {} + ) => { + const { item } = ctx + const { mutate } = useCart() as any + + return useCallback( + debounce(async (input: UpdateItemInput<T>) => { + const itemId = input.id ?? item?.id + const productId = input.productId ?? item?.productId + const variantId = input.productId ?? item?.variantId + if (!itemId || !productId || !variantId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ + input: { + item: { + productId, + variantId, + quantity: input.quantity, + }, + itemId, + }, + }) + await mutate(data, false) + return data + }, ctx.wait ?? 500), + [fetch, mutate] + ) + }, +} diff --git a/framework/shopify/commerce.config.json b/framework/shopify/commerce.config.json new file mode 100644 index 00000000..b30ab39d --- /dev/null +++ b/framework/shopify/commerce.config.json @@ -0,0 +1,6 @@ +{ + "provider": "shopify", + "features": { + "wishlist": false + } +} diff --git a/framework/shopify/common/get-all-pages.ts b/framework/shopify/common/get-all-pages.ts new file mode 100644 index 00000000..54231ed0 --- /dev/null +++ b/framework/shopify/common/get-all-pages.ts @@ -0,0 +1,42 @@ +import { getConfig, ShopifyConfig } from '../api' +import { PageEdge } from '../schema' +import { getAllPagesQuery } from '../utils/queries' + +type Variables = { + first?: number +} + +type ReturnType = { + pages: Page[] +} + +export type Page = { + id: string + name: string + url: string + sort_order?: number + body: string +} + +const getAllPages = async (options?: { + variables?: Variables + config: ShopifyConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables = { first: 250 } } = options ?? {} + config = getConfig(config) + const { locale } = config + const { data } = await config.fetch(getAllPagesQuery, { variables }) + + const pages = data.pages?.edges?.map( + ({ node: { title: name, handle, ...node } }: PageEdge) => ({ + ...node, + url: `/${locale}/${handle}`, + name, + }) + ) + + return { pages } +} + +export default getAllPages diff --git a/framework/shopify/common/get-page.ts b/framework/shopify/common/get-page.ts new file mode 100644 index 00000000..be934aa4 --- /dev/null +++ b/framework/shopify/common/get-page.ts @@ -0,0 +1,37 @@ +import { getConfig, ShopifyConfig } from '../api' +import getPageQuery from '../utils/queries/get-page-query' +import { Page } from './get-all-pages' + +type Variables = { + id: string +} + +export type GetPageResult<T extends { page?: any } = { page?: Page }> = T + +const getPage = async (options: { + variables: Variables + config: ShopifyConfig + preview?: boolean +}): Promise<GetPageResult> => { + let { config, variables } = options ?? {} + + config = getConfig(config) + const { locale } = config + + const { data } = await config.fetch(getPageQuery, { + variables, + }) + const page = data.node + + return { + page: page + ? { + ...page, + name: page.title, + url: `/${locale}/${page.handle}`, + } + : null, + } +} + +export default getPage diff --git a/framework/shopify/common/get-site-info.ts b/framework/shopify/common/get-site-info.ts new file mode 100644 index 00000000..cbbacf5b --- /dev/null +++ b/framework/shopify/common/get-site-info.ts @@ -0,0 +1,31 @@ +import getCategories, { Category } from '../utils/get-categories' +import getVendors, { Brands } from '../utils/get-vendors' + +import { getConfig, ShopifyConfig } from '../api' + +export type GetSiteInfoResult< + T extends { categories: any[]; brands: any[] } = { + categories: Category[] + brands: Brands + } +> = T + +const getSiteInfo = async (options?: { + variables?: any + config: ShopifyConfig + preview?: boolean +}): Promise<GetSiteInfoResult> => { + let { config } = options ?? {} + + config = getConfig(config) + + const categories = await getCategories(config) + const brands = await getVendors(config) + + return { + categories, + brands, + } +} + +export default getSiteInfo diff --git a/framework/shopify/const.ts b/framework/shopify/const.ts new file mode 100644 index 00000000..06fbe505 --- /dev/null +++ b/framework/shopify/const.ts @@ -0,0 +1,13 @@ +export const SHOPIFY_CHECKOUT_ID_COOKIE = 'shopify_checkoutId' + +export const SHOPIFY_CHECKOUT_URL_COOKIE = 'shopify_checkoutUrl' + +export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken' + +export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN + +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 diff --git a/framework/shopify/customer/get-customer-id.ts b/framework/shopify/customer/get-customer-id.ts new file mode 100644 index 00000000..ca096645 --- /dev/null +++ b/framework/shopify/customer/get-customer-id.ts @@ -0,0 +1,24 @@ +import { getConfig, ShopifyConfig } from '../api' +import getCustomerIdQuery from '../utils/queries/get-customer-id-query' +import Cookies from 'js-cookie' + +async function getCustomerId({ + customerToken: customerAccesToken, + config, +}: { + customerToken: string + config?: ShopifyConfig +}): Promise<number | undefined> { + config = getConfig(config) + + const { data } = await config.fetch(getCustomerIdQuery, { + variables: { + customerAccesToken: + customerAccesToken || Cookies.get(config.customerCookie), + }, + }) + + return data.customer?.id +} + +export default getCustomerId diff --git a/framework/shopify/customer/index.ts b/framework/shopify/customer/index.ts new file mode 100644 index 00000000..6c903ecc --- /dev/null +++ b/framework/shopify/customer/index.ts @@ -0,0 +1 @@ +export { default as useCustomer } from './use-customer' diff --git a/framework/shopify/customer/use-customer.tsx b/framework/shopify/customer/use-customer.tsx new file mode 100644 index 00000000..7b600838 --- /dev/null +++ b/framework/shopify/customer/use-customer.tsx @@ -0,0 +1,31 @@ +import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' +import { Customer } from '@commerce/types' +import { SWRHook } from '@commerce/utils/types' +import { getCustomerQuery, getCustomerToken } from '../utils' + +export default useCustomer as UseCustomer<typeof handler> + +export const handler: SWRHook<Customer | null> = { + fetchOptions: { + query: getCustomerQuery, + }, + async fetcher({ options, fetch }) { + const customerAccessToken = getCustomerToken() + if (customerAccessToken) { + const data = await fetch({ + ...options, + variables: { customerAccessToken: getCustomerToken() }, + }) + return data.customer + } + return null + }, + useHook: ({ useData }) => (input) => { + return useData({ + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions, + }, + }) + }, +} diff --git a/framework/shopify/fetcher.ts b/framework/shopify/fetcher.ts new file mode 100644 index 00000000..a6915050 --- /dev/null +++ b/framework/shopify/fetcher.ts @@ -0,0 +1,23 @@ +import { Fetcher } from '@commerce/utils/types' +import { API_TOKEN, API_URL } from './const' +import { handleFetchResponse } from './utils' + +const fetcher: Fetcher = async ({ + url = API_URL, + method = 'POST', + variables, + query, +}) => { + return handleFetchResponse( + await fetch(url, { + method, + body: JSON.stringify({ query, variables }), + headers: { + 'X-Shopify-Storefront-Access-Token': API_TOKEN!, + 'Content-Type': 'application/json', + }, + }) + ) +} + +export default fetcher diff --git a/framework/shopify/index.tsx b/framework/shopify/index.tsx new file mode 100644 index 00000000..5b25d6b2 --- /dev/null +++ b/framework/shopify/index.tsx @@ -0,0 +1,39 @@ +import * as React from 'react' +import { ReactNode } from 'react' + +import { + CommerceConfig, + CommerceProvider as CoreCommerceProvider, + useCommerce as useCoreCommerce, +} from '@commerce' + +import { shopifyProvider, ShopifyProvider } from './provider' +import { SHOPIFY_CHECKOUT_ID_COOKIE } from './const' + +export { shopifyProvider } +export type { ShopifyProvider } + +export const shopifyConfig: CommerceConfig = { + locale: 'en-us', + cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, +} + +export type ShopifyConfig = Partial<CommerceConfig> + +export type ShopifyProps = { + children?: ReactNode + locale: string +} & ShopifyConfig + +export function CommerceProvider({ children, ...config }: ShopifyProps) { + return ( + <CoreCommerceProvider + provider={shopifyProvider} + config={{ ...shopifyConfig, ...config }} + > + {children} + </CoreCommerceProvider> + ) +} + +export const useCommerce = () => useCoreCommerce() diff --git a/framework/shopify/next.config.js b/framework/shopify/next.config.js new file mode 100644 index 00000000..e9d48c02 --- /dev/null +++ b/framework/shopify/next.config.js @@ -0,0 +1,8 @@ +const commerce = require('./commerce.config.json') + +module.exports = { + commerce, + images: { + domains: ['cdn.shopify.com'], + }, +} diff --git a/framework/shopify/product/get-all-collections.ts b/framework/shopify/product/get-all-collections.ts new file mode 100644 index 00000000..15c4bc51 --- /dev/null +++ b/framework/shopify/product/get-all-collections.ts @@ -0,0 +1,29 @@ +import { CollectionEdge } from '../schema' +import { getConfig, ShopifyConfig } from '../api' +import getAllCollectionsQuery from '../utils/queries/get-all-collections-query' + +const getAllCollections = async (options?: { + variables?: any + config: ShopifyConfig + preview?: boolean +}) => { + let { config, variables = { first: 250 } } = options ?? {} + config = getConfig(config) + + const { data } = await config.fetch(getAllCollectionsQuery, { variables }) + const edges = data.collections?.edges ?? [] + + const categories = edges.map( + ({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({ + entityId, + name, + path: `/${handle}`, + }) + ) + + return { + categories, + } +} + +export default getAllCollections diff --git a/framework/shopify/product/get-all-product-paths.ts b/framework/shopify/product/get-all-product-paths.ts new file mode 100644 index 00000000..e8ee0406 --- /dev/null +++ b/framework/shopify/product/get-all-product-paths.ts @@ -0,0 +1,41 @@ +import { getConfig, ShopifyConfig } from '../api' +import { ProductEdge } from '../schema' +import getAllProductsPathsQuery from '../utils/queries/get-all-products-paths-query' + +type ProductPath = { + path: string +} + +export type ProductPathNode = { + node: ProductPath +} + +type ReturnType = { + products: ProductPathNode[] +} + +const getAllProductPaths = async (options?: { + variables?: any + config?: ShopifyConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables = { first: 100, sortKey: 'BEST_SELLING' } } = + options ?? {} + config = getConfig(config) + + const { data } = await config.fetch(getAllProductsPathsQuery, { + variables, + }) + + return { + products: data.products?.edges?.map( + ({ node: { handle } }: ProductEdge) => ({ + node: { + path: `/${handle}`, + }, + }) + ), + } +} + +export default getAllProductPaths diff --git a/framework/shopify/product/get-all-products.ts b/framework/shopify/product/get-all-products.ts new file mode 100644 index 00000000..3915abeb --- /dev/null +++ b/framework/shopify/product/get-all-products.ts @@ -0,0 +1,39 @@ +import { GraphQLFetcherResult } from '@commerce/api' +import { getConfig, ShopifyConfig } from '../api' +import { ProductEdge } from '../schema' +import { getAllProductsQuery } from '../utils/queries' +import { normalizeProduct } from '../utils/normalize' +import { Product } from '@commerce/types' + +type Variables = { + first?: number + field?: string +} + +type ReturnType = { + products: Product[] +} + +const getAllProducts = async (options: { + variables?: Variables + config?: ShopifyConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables = { first: 250 } } = options ?? {} + config = getConfig(config) + + const { data }: GraphQLFetcherResult = await config.fetch( + getAllProductsQuery, + { variables } + ) + + const products = data.products?.edges?.map(({ node: p }: ProductEdge) => + normalizeProduct(p) + ) + + return { + products, + } +} + +export default getAllProducts diff --git a/framework/shopify/product/get-product.ts b/framework/shopify/product/get-product.ts new file mode 100644 index 00000000..1d861e1a --- /dev/null +++ b/framework/shopify/product/get-product.ts @@ -0,0 +1,31 @@ +import { GraphQLFetcherResult } from '@commerce/api' +import { getConfig, ShopifyConfig } from '../api' +import { normalizeProduct, getProductQuery } from '../utils' + +type Variables = { + slug: string +} + +type ReturnType = { + product: any +} + +const getProduct = async (options: { + variables: Variables + config: ShopifyConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables } = options ?? {} + config = getConfig(config) + + const { data }: GraphQLFetcherResult = await config.fetch(getProductQuery, { + variables, + }) + const { productByHandle } = data + + return { + product: productByHandle ? normalizeProduct(productByHandle) : null, + } +} + +export default getProduct diff --git a/framework/shopify/product/use-price.tsx b/framework/shopify/product/use-price.tsx new file mode 100644 index 00000000..0174faf5 --- /dev/null +++ b/framework/shopify/product/use-price.tsx @@ -0,0 +1,2 @@ +export * from '@commerce/product/use-price' +export { default } from '@commerce/product/use-price' diff --git a/framework/shopify/product/use-search.tsx b/framework/shopify/product/use-search.tsx new file mode 100644 index 00000000..bf812af3 --- /dev/null +++ b/framework/shopify/product/use-search.tsx @@ -0,0 +1,78 @@ +import { SWRHook } from '@commerce/utils/types' +import useSearch, { UseSearch } from '@commerce/product/use-search' + +import { ProductEdge } from '../schema' +import { + getAllProductsQuery, + getCollectionProductsQuery, + getSearchVariables, + normalizeProduct, +} from '../utils' + +import { Product } from '@commerce/types' + +export default useSearch as UseSearch<typeof handler> + +export type SearchProductsInput = { + search?: string + categoryId?: string + brandId?: string + sort?: string +} + +export type SearchProductsData = { + products: Product[] + found: boolean +} + +export const handler: SWRHook< + SearchProductsData, + SearchProductsInput, + SearchProductsInput +> = { + fetchOptions: { + query: getAllProductsQuery, + }, + async fetcher({ input, options, fetch }) { + const { categoryId, brandId } = input + + const data = await fetch({ + query: categoryId ? getCollectionProductsQuery : options.query, + method: options?.method, + variables: getSearchVariables(input), + }) + + let edges + + if (categoryId) { + edges = data.node?.products?.edges ?? [] + if (brandId) { + edges = edges.filter( + ({ node: { vendor } }: ProductEdge) => + vendor.replace(/\s+/g, '-').toLowerCase() === brandId + ) + } + } else { + edges = data.products?.edges ?? [] + } + + return { + products: edges.map(({ node }: ProductEdge) => normalizeProduct(node)), + found: !!edges.length, + } + }, + 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/framework/shopify/provider.ts b/framework/shopify/provider.ts new file mode 100644 index 00000000..00db5c1d --- /dev/null +++ b/framework/shopify/provider.ts @@ -0,0 +1,27 @@ +import { SHOPIFY_CHECKOUT_ID_COOKIE } from './const' + +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' + +import fetcher from './fetcher' + +export const shopifyProvider = { + locale: 'en-us', + cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE, + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, +} + +export type ShopifyProvider = typeof shopifyProvider diff --git a/framework/shopify/schema.d.ts b/framework/shopify/schema.d.ts new file mode 100644 index 00000000..b1b23a3e --- /dev/null +++ b/framework/shopify/schema.d.ts @@ -0,0 +1,4985 @@ +export type Maybe<T> = T | null +export type Exact<T extends { [key: string]: unknown }> = { + [K in keyof T]: T[K] +} +export type MakeOptional<T, K extends keyof T> = Omit<T, K> & + { [SubKey in K]?: Maybe<T[SubKey]> } +export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & + { [SubKey in K]: Maybe<T[SubKey]> } +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string + String: string + Boolean: boolean + Int: number + Float: number + /** An ISO-8601 encoded UTC date time string. Example value: `"2019-07-03T20:47:55Z"`. */ + DateTime: any + /** A signed decimal number, which supports arbitrary precision and is serialized as a string. Example value: `"29.99"`. */ + Decimal: any + /** A string containing HTML code. Example value: `"<p>Grey cotton knit sweater.</p>"`. */ + HTML: any + /** A monetary value string. Example value: `"100.57"`. */ + Money: any + /** + * An RFC 3986 and RFC 3987 compliant URI string. + * + * Example value: `"https://johns-apparel.myshopify.com"`. + * + */ + URL: any +} + +/** A version of the API. */ +export type ApiVersion = { + __typename?: 'ApiVersion' + /** The human-readable name of the version. */ + displayName: Scalars['String'] + /** The unique identifier of an ApiVersion. All supported API versions have a date-based (YYYY-MM) or `unstable` handle. */ + handle: Scalars['String'] + /** Whether the version is supported by Shopify. */ + supported: Scalars['Boolean'] +} + +/** Details about the gift card used on the checkout. */ +export type AppliedGiftCard = Node & { + __typename?: 'AppliedGiftCard' + /** + * The amount that was taken from the gift card by applying it. + * @deprecated Use `amountUsedV2` instead + */ + amountUsed: Scalars['Money'] + /** The amount that was taken from the gift card by applying it. */ + amountUsedV2: MoneyV2 + /** + * The amount left on the gift card. + * @deprecated Use `balanceV2` instead + */ + balance: Scalars['Money'] + /** The amount left on the gift card. */ + balanceV2: MoneyV2 + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The last characters of the gift card. */ + lastCharacters: Scalars['String'] + /** The amount that was applied to the checkout in its currency. */ + presentmentAmountUsed: MoneyV2 +} + +/** An article in an online store blog. */ +export type Article = Node & { + __typename?: 'Article' + /** + * The article's author. + * @deprecated Use `authorV2` instead + */ + author: ArticleAuthor + /** The article's author. */ + authorV2?: Maybe<ArticleAuthor> + /** The blog that the article belongs to. */ + blog: Blog + /** List of comments posted on the article. */ + comments: CommentConnection + /** Stripped content of the article, single line with HTML tags removed. */ + content: Scalars['String'] + /** The content of the article, complete with HTML formatting. */ + contentHtml: Scalars['HTML'] + /** Stripped excerpt of the article, single line with HTML tags removed. */ + excerpt?: Maybe<Scalars['String']> + /** The excerpt of the article, complete with HTML formatting. */ + excerptHtml?: Maybe<Scalars['HTML']> + /** A human-friendly unique string for the Article automatically generated from its title. */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The image associated with the article. */ + image?: Maybe<Image> + /** The date and time when the article was published. */ + publishedAt: Scalars['DateTime'] + /** The article’s SEO information. */ + seo?: Maybe<Seo> + /** A categorization that a article can be tagged with. */ + tags: Array<Scalars['String']> + /** The article’s name. */ + title: Scalars['String'] + /** The url pointing to the article accessible from the web. */ + url: Scalars['URL'] +} + +/** An article in an online store blog. */ +export type ArticleCommentsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** An article in an online store blog. */ +export type ArticleContentArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** An article in an online store blog. */ +export type ArticleExcerptArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** An article in an online store blog. */ +export type ArticleImageArgs = { + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> +} + +/** The author of an article. */ +export type ArticleAuthor = { + __typename?: 'ArticleAuthor' + /** The author's bio. */ + bio?: Maybe<Scalars['String']> + /** The author’s email. */ + email: Scalars['String'] + /** The author's first name. */ + firstName: Scalars['String'] + /** The author's last name. */ + lastName: Scalars['String'] + /** The author's full name. */ + name: Scalars['String'] +} + +/** An auto-generated type for paginating through multiple Articles. */ +export type ArticleConnection = { + __typename?: 'ArticleConnection' + /** A list of edges. */ + edges: Array<ArticleEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Article and a cursor during pagination. */ +export type ArticleEdge = { + __typename?: 'ArticleEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ArticleEdge. */ + node: Article +} + +/** The set of valid sort keys for the Article query. */ +export enum ArticleSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `blog_title` value. */ + BlogTitle = 'BLOG_TITLE', + /** Sort by the `author` value. */ + Author = 'AUTHOR', + /** Sort by the `updated_at` value. */ + UpdatedAt = 'UPDATED_AT', + /** Sort by the `published_at` value. */ + PublishedAt = 'PUBLISHED_AT', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** Represents a generic custom attribute. */ +export type Attribute = { + __typename?: 'Attribute' + /** Key or name of the attribute. */ + key: Scalars['String'] + /** Value of the attribute. */ + value?: Maybe<Scalars['String']> +} + +/** Specifies the input fields required for an attribute. */ +export type AttributeInput = { + /** Key or name of the attribute. */ + key: Scalars['String'] + /** Value of the attribute. */ + value: Scalars['String'] +} + +/** Automatic discount applications capture the intentions of a discount that was automatically applied. */ +export type AutomaticDiscountApplication = DiscountApplication & { + __typename?: 'AutomaticDiscountApplication' + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The title of the application. */ + title: Scalars['String'] + /** The value of the discount application. */ + value: PricingValue +} + +/** A collection of available shipping rates for a checkout. */ +export type AvailableShippingRates = { + __typename?: 'AvailableShippingRates' + /** + * Whether or not the shipping rates are ready. + * The `shippingRates` field is `null` when this value is `false`. + * This field should be polled until its value becomes `true`. + */ + ready: Scalars['Boolean'] + /** The fetched shipping rates. `null` until the `ready` field is `true`. */ + shippingRates?: Maybe<Array<ShippingRate>> +} + +/** An online store blog. */ +export type Blog = Node & { + __typename?: 'Blog' + /** Find an article by its handle. */ + articleByHandle?: Maybe<Article> + /** List of the blog's articles. */ + articles: ArticleConnection + /** The authors who have contributed to the blog. */ + authors: Array<ArticleAuthor> + /** A human-friendly unique string for the Blog automatically generated from its title. */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The blog's SEO information. */ + seo?: Maybe<Seo> + /** The blogs’s title. */ + title: Scalars['String'] + /** The url pointing to the blog accessible from the web. */ + url: Scalars['URL'] +} + +/** An online store blog. */ +export type BlogArticleByHandleArgs = { + handle: Scalars['String'] +} + +/** An online store blog. */ +export type BlogArticlesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ArticleSortKeys> + query?: Maybe<Scalars['String']> +} + +/** An auto-generated type for paginating through multiple Blogs. */ +export type BlogConnection = { + __typename?: 'BlogConnection' + /** A list of edges. */ + edges: Array<BlogEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Blog and a cursor during pagination. */ +export type BlogEdge = { + __typename?: 'BlogEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of BlogEdge. */ + node: Blog +} + +/** The set of valid sort keys for the Blog query. */ +export enum BlogSortKeys { + /** Sort by the `handle` value. */ + Handle = 'HANDLE', + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** Card brand, such as Visa or Mastercard, which can be used for payments. */ +export enum CardBrand { + /** Visa */ + Visa = 'VISA', + /** Mastercard */ + Mastercard = 'MASTERCARD', + /** Discover */ + Discover = 'DISCOVER', + /** American Express */ + AmericanExpress = 'AMERICAN_EXPRESS', + /** Diners Club */ + DinersClub = 'DINERS_CLUB', + /** JCB */ + Jcb = 'JCB', +} + +/** A container for all the information required to checkout items and pay. */ +export type Checkout = Node & { + __typename?: 'Checkout' + /** The gift cards used on the checkout. */ + appliedGiftCards: Array<AppliedGiftCard> + /** + * The available shipping rates for this Checkout. + * Should only be used when checkout `requiresShipping` is `true` and + * the shipping address is valid. + */ + availableShippingRates?: Maybe<AvailableShippingRates> + /** The date and time when the checkout was completed. */ + completedAt?: Maybe<Scalars['DateTime']> + /** The date and time when the checkout was created. */ + createdAt: Scalars['DateTime'] + /** The currency code for the Checkout. */ + currencyCode: CurrencyCode + /** A list of extra information that is added to the checkout. */ + customAttributes: Array<Attribute> + /** + * The customer associated with the checkout. + * @deprecated This field will always return null. If you have an authentication token for the customer, you can use the `customer` field on the query root to retrieve it. + */ + customer?: Maybe<Customer> + /** Discounts that have been applied on the checkout. */ + discountApplications: DiscountApplicationConnection + /** The email attached to this checkout. */ + email?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** A list of line item objects, each one containing information about an item in the checkout. */ + lineItems: CheckoutLineItemConnection + /** The sum of all the prices of all the items in the checkout. Duties, taxes, shipping and discounts excluded. */ + lineItemsSubtotalPrice: MoneyV2 + /** The note associated with the checkout. */ + note?: Maybe<Scalars['String']> + /** The resulting order from a paid checkout. */ + order?: Maybe<Order> + /** The Order Status Page for this Checkout, null when checkout is not completed. */ + orderStatusUrl?: Maybe<Scalars['URL']> + /** + * The amount left to be paid. This is equal to the cost of the line items, taxes and shipping minus discounts and gift cards. + * @deprecated Use `paymentDueV2` instead + */ + paymentDue: Scalars['Money'] + /** The amount left to be paid. This is equal to the cost of the line items, duties, taxes and shipping minus discounts and gift cards. */ + paymentDueV2: MoneyV2 + /** + * Whether or not the Checkout is ready and can be completed. Checkouts may + * have asynchronous operations that can take time to finish. If you want + * to complete a checkout or ensure all the fields are populated and up to + * date, polling is required until the value is true. + */ + ready: Scalars['Boolean'] + /** States whether or not the fulfillment requires shipping. */ + requiresShipping: Scalars['Boolean'] + /** The shipping address to where the line items will be shipped. */ + shippingAddress?: Maybe<MailingAddress> + /** The discounts that have been allocated onto the shipping line by discount applications. */ + shippingDiscountAllocations: Array<DiscountAllocation> + /** Once a shipping rate is selected by the customer it is transitioned to a `shipping_line` object. */ + shippingLine?: Maybe<ShippingRate> + /** + * Price of the checkout before shipping and taxes. + * @deprecated Use `subtotalPriceV2` instead + */ + subtotalPrice: Scalars['Money'] + /** Price of the checkout before duties, shipping and taxes. */ + subtotalPriceV2: MoneyV2 + /** Specifies if the Checkout is tax exempt. */ + taxExempt: Scalars['Boolean'] + /** Specifies if taxes are included in the line item and shipping line prices. */ + taxesIncluded: Scalars['Boolean'] + /** + * The sum of all the prices of all the items in the checkout, taxes and discounts included. + * @deprecated Use `totalPriceV2` instead + */ + totalPrice: Scalars['Money'] + /** The sum of all the prices of all the items in the checkout, duties, taxes and discounts included. */ + totalPriceV2: MoneyV2 + /** + * The sum of all the taxes applied to the line items and shipping lines in the checkout. + * @deprecated Use `totalTaxV2` instead + */ + totalTax: Scalars['Money'] + /** The sum of all the taxes applied to the line items and shipping lines in the checkout. */ + totalTaxV2: MoneyV2 + /** The date and time when the checkout was last updated. */ + updatedAt: Scalars['DateTime'] + /** The url pointing to the checkout accessible from the web. */ + webUrl: Scalars['URL'] +} + +/** A container for all the information required to checkout items and pay. */ +export type CheckoutDiscountApplicationsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** A container for all the information required to checkout items and pay. */ +export type CheckoutLineItemsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** Specifies the fields required to update a checkout's attributes. */ +export type CheckoutAttributesUpdateInput = { + /** The text of an optional note that a shop owner can attach to the checkout. */ + note?: Maybe<Scalars['String']> + /** A list of extra information that is added to the checkout. */ + customAttributes?: Maybe<Array<AttributeInput>> + /** + * Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + * The required attributes are city, province, and country. + * Full validation of the addresses is still done at complete time. + */ + allowPartialAddresses?: Maybe<Scalars['Boolean']> +} + +/** Return type for `checkoutAttributesUpdate` mutation. */ +export type CheckoutAttributesUpdatePayload = { + __typename?: 'CheckoutAttributesUpdatePayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to update a checkout's attributes. */ +export type CheckoutAttributesUpdateV2Input = { + /** The text of an optional note that a shop owner can attach to the checkout. */ + note?: Maybe<Scalars['String']> + /** A list of extra information that is added to the checkout. */ + customAttributes?: Maybe<Array<AttributeInput>> + /** + * Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + * The required attributes are city, province, and country. + * Full validation of the addresses is still done at complete time. + */ + allowPartialAddresses?: Maybe<Scalars['Boolean']> +} + +/** Return type for `checkoutAttributesUpdateV2` mutation. */ +export type CheckoutAttributesUpdateV2Payload = { + __typename?: 'CheckoutAttributesUpdateV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteFree` mutation. */ +export type CheckoutCompleteFreePayload = { + __typename?: 'CheckoutCompleteFreePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithCreditCard` mutation. */ +export type CheckoutCompleteWithCreditCardPayload = { + __typename?: 'CheckoutCompleteWithCreditCardPayload' + /** The checkout on which the payment was applied. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithCreditCardV2` mutation. */ +export type CheckoutCompleteWithCreditCardV2Payload = { + __typename?: 'CheckoutCompleteWithCreditCardV2Payload' + /** The checkout on which the payment was applied. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithTokenizedPayment` mutation. */ +export type CheckoutCompleteWithTokenizedPaymentPayload = { + __typename?: 'CheckoutCompleteWithTokenizedPaymentPayload' + /** The checkout on which the payment was applied. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithTokenizedPaymentV2` mutation. */ +export type CheckoutCompleteWithTokenizedPaymentV2Payload = { + __typename?: 'CheckoutCompleteWithTokenizedPaymentV2Payload' + /** The checkout on which the payment was applied. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithTokenizedPaymentV3` mutation. */ +export type CheckoutCompleteWithTokenizedPaymentV3Payload = { + __typename?: 'CheckoutCompleteWithTokenizedPaymentV3Payload' + /** The checkout on which the payment was applied. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to create a checkout. */ +export type CheckoutCreateInput = { + /** The email with which the customer wants to checkout. */ + email?: Maybe<Scalars['String']> + /** A list of line item objects, each one containing information about an item in the checkout. */ + lineItems?: Maybe<Array<CheckoutLineItemInput>> + /** The shipping address to where the line items will be shipped. */ + shippingAddress?: Maybe<MailingAddressInput> + /** The text of an optional note that a shop owner can attach to the checkout. */ + note?: Maybe<Scalars['String']> + /** A list of extra information that is added to the checkout. */ + customAttributes?: Maybe<Array<AttributeInput>> + /** + * Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + * The required attributes are city, province, and country. + * Full validation of addresses is still done at complete time. + */ + allowPartialAddresses?: Maybe<Scalars['Boolean']> + /** + * The three-letter currency code of one of the shop's enabled presentment currencies. + * Including this field creates a checkout in the specified currency. By default, new + * checkouts are created in the shop's primary currency. + */ + presentmentCurrencyCode?: Maybe<CurrencyCode> +} + +/** Return type for `checkoutCreate` mutation. */ +export type CheckoutCreatePayload = { + __typename?: 'CheckoutCreatePayload' + /** The new checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCustomerAssociate` mutation. */ +export type CheckoutCustomerAssociatePayload = { + __typename?: 'CheckoutCustomerAssociatePayload' + /** The updated checkout object. */ + checkout: Checkout + /** The associated customer object. */ + customer?: Maybe<Customer> + /** List of errors that occurred executing the mutation. */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCustomerAssociateV2` mutation. */ +export type CheckoutCustomerAssociateV2Payload = { + __typename?: 'CheckoutCustomerAssociateV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** The associated customer object. */ + customer?: Maybe<Customer> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCustomerDisassociate` mutation. */ +export type CheckoutCustomerDisassociatePayload = { + __typename?: 'CheckoutCustomerDisassociatePayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCustomerDisassociateV2` mutation. */ +export type CheckoutCustomerDisassociateV2Payload = { + __typename?: 'CheckoutCustomerDisassociateV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutDiscountCodeApply` mutation. */ +export type CheckoutDiscountCodeApplyPayload = { + __typename?: 'CheckoutDiscountCodeApplyPayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutDiscountCodeApplyV2` mutation. */ +export type CheckoutDiscountCodeApplyV2Payload = { + __typename?: 'CheckoutDiscountCodeApplyV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutDiscountCodeRemove` mutation. */ +export type CheckoutDiscountCodeRemovePayload = { + __typename?: 'CheckoutDiscountCodeRemovePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutEmailUpdate` mutation. */ +export type CheckoutEmailUpdatePayload = { + __typename?: 'CheckoutEmailUpdatePayload' + /** The checkout object with the updated email. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutEmailUpdateV2` mutation. */ +export type CheckoutEmailUpdateV2Payload = { + __typename?: 'CheckoutEmailUpdateV2Payload' + /** The checkout object with the updated email. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Possible error codes that could be returned by CheckoutUserError. */ +export enum CheckoutErrorCode { + /** Input value is blank. */ + Blank = 'BLANK', + /** Input value is invalid. */ + Invalid = 'INVALID', + /** Input value is too long. */ + TooLong = 'TOO_LONG', + /** Input value is not present. */ + Present = 'PRESENT', + /** Input value should be less than maximum allowed value. */ + LessThan = 'LESS_THAN', + /** Input value should be greater than or equal to minimum allowed value. */ + GreaterThanOrEqualTo = 'GREATER_THAN_OR_EQUAL_TO', + /** Input value should be less or equal to maximum allowed value. */ + LessThanOrEqualTo = 'LESS_THAN_OR_EQUAL_TO', + /** Checkout is already completed. */ + AlreadyCompleted = 'ALREADY_COMPLETED', + /** Checkout is locked. */ + Locked = 'LOCKED', + /** Input value is not supported. */ + NotSupported = 'NOT_SUPPORTED', + /** Input email contains an invalid domain name. */ + BadDomain = 'BAD_DOMAIN', + /** Input Zip is invalid for country provided. */ + InvalidForCountry = 'INVALID_FOR_COUNTRY', + /** Input Zip is invalid for country and province provided. */ + InvalidForCountryAndProvince = 'INVALID_FOR_COUNTRY_AND_PROVINCE', + /** Invalid state in country. */ + InvalidStateInCountry = 'INVALID_STATE_IN_COUNTRY', + /** Invalid province in country. */ + InvalidProvinceInCountry = 'INVALID_PROVINCE_IN_COUNTRY', + /** Invalid region in country. */ + InvalidRegionInCountry = 'INVALID_REGION_IN_COUNTRY', + /** Shipping rate expired. */ + ShippingRateExpired = 'SHIPPING_RATE_EXPIRED', + /** Gift card cannot be applied to a checkout that contains a gift card. */ + GiftCardUnusable = 'GIFT_CARD_UNUSABLE', + /** Gift card is disabled. */ + GiftCardDisabled = 'GIFT_CARD_DISABLED', + /** Gift card code is invalid. */ + GiftCardCodeInvalid = 'GIFT_CARD_CODE_INVALID', + /** Gift card has already been applied. */ + GiftCardAlreadyApplied = 'GIFT_CARD_ALREADY_APPLIED', + /** Gift card currency does not match checkout currency. */ + GiftCardCurrencyMismatch = 'GIFT_CARD_CURRENCY_MISMATCH', + /** Gift card is expired. */ + GiftCardExpired = 'GIFT_CARD_EXPIRED', + /** Gift card has no funds left. */ + GiftCardDepleted = 'GIFT_CARD_DEPLETED', + /** Gift card was not found. */ + GiftCardNotFound = 'GIFT_CARD_NOT_FOUND', + /** Cart does not meet discount requirements notice. */ + CartDoesNotMeetDiscountRequirementsNotice = 'CART_DOES_NOT_MEET_DISCOUNT_REQUIREMENTS_NOTICE', + /** Discount expired. */ + DiscountExpired = 'DISCOUNT_EXPIRED', + /** Discount disabled. */ + DiscountDisabled = 'DISCOUNT_DISABLED', + /** Discount limit reached. */ + DiscountLimitReached = 'DISCOUNT_LIMIT_REACHED', + /** Discount not found. */ + DiscountNotFound = 'DISCOUNT_NOT_FOUND', + /** Customer already used once per customer discount notice. */ + CustomerAlreadyUsedOncePerCustomerDiscountNotice = 'CUSTOMER_ALREADY_USED_ONCE_PER_CUSTOMER_DISCOUNT_NOTICE', + /** Checkout is already completed. */ + Empty = 'EMPTY', + /** Not enough in stock. */ + NotEnoughInStock = 'NOT_ENOUGH_IN_STOCK', + /** Missing payment input. */ + MissingPaymentInput = 'MISSING_PAYMENT_INPUT', + /** The amount of the payment does not match the value to be paid. */ + TotalPriceMismatch = 'TOTAL_PRICE_MISMATCH', + /** Line item was not found in checkout. */ + LineItemNotFound = 'LINE_ITEM_NOT_FOUND', + /** Unable to apply discount. */ + UnableToApply = 'UNABLE_TO_APPLY', + /** Discount already applied. */ + DiscountAlreadyApplied = 'DISCOUNT_ALREADY_APPLIED', +} + +/** Return type for `checkoutGiftCardApply` mutation. */ +export type CheckoutGiftCardApplyPayload = { + __typename?: 'CheckoutGiftCardApplyPayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutGiftCardRemove` mutation. */ +export type CheckoutGiftCardRemovePayload = { + __typename?: 'CheckoutGiftCardRemovePayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutGiftCardRemoveV2` mutation. */ +export type CheckoutGiftCardRemoveV2Payload = { + __typename?: 'CheckoutGiftCardRemoveV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutGiftCardsAppend` mutation. */ +export type CheckoutGiftCardsAppendPayload = { + __typename?: 'CheckoutGiftCardsAppendPayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** A single line item in the checkout, grouped by variant and attributes. */ +export type CheckoutLineItem = Node & { + __typename?: 'CheckoutLineItem' + /** Extra information in the form of an array of Key-Value pairs about the line item. */ + customAttributes: Array<Attribute> + /** The discounts that have been allocated onto the checkout line item by discount applications. */ + discountAllocations: Array<DiscountAllocation> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The quantity of the line item. */ + quantity: Scalars['Int'] + /** Title of the line item. Defaults to the product's title. */ + title: Scalars['String'] + /** Unit price of the line item. */ + unitPrice?: Maybe<MoneyV2> + /** Product variant of the line item. */ + variant?: Maybe<ProductVariant> +} + +/** An auto-generated type for paginating through multiple CheckoutLineItems. */ +export type CheckoutLineItemConnection = { + __typename?: 'CheckoutLineItemConnection' + /** A list of edges. */ + edges: Array<CheckoutLineItemEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one CheckoutLineItem and a cursor during pagination. */ +export type CheckoutLineItemEdge = { + __typename?: 'CheckoutLineItemEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of CheckoutLineItemEdge. */ + node: CheckoutLineItem +} + +/** Specifies the input fields to create a line item on a checkout. */ +export type CheckoutLineItemInput = { + /** Extra information in the form of an array of Key-Value pairs about the line item. */ + customAttributes?: Maybe<Array<AttributeInput>> + /** The quantity of the line item. */ + quantity: Scalars['Int'] + /** The identifier of the product variant for the line item. */ + variantId: Scalars['ID'] +} + +/** Specifies the input fields to update a line item on the checkout. */ +export type CheckoutLineItemUpdateInput = { + /** The identifier of the line item. */ + id?: Maybe<Scalars['ID']> + /** The variant identifier of the line item. */ + variantId?: Maybe<Scalars['ID']> + /** The quantity of the line item. */ + quantity?: Maybe<Scalars['Int']> + /** Extra information in the form of an array of Key-Value pairs about the line item. */ + customAttributes?: Maybe<Array<AttributeInput>> +} + +/** Return type for `checkoutLineItemsAdd` mutation. */ +export type CheckoutLineItemsAddPayload = { + __typename?: 'CheckoutLineItemsAddPayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutLineItemsRemove` mutation. */ +export type CheckoutLineItemsRemovePayload = { + __typename?: 'CheckoutLineItemsRemovePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutLineItemsReplace` mutation. */ +export type CheckoutLineItemsReplacePayload = { + __typename?: 'CheckoutLineItemsReplacePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + userErrors: Array<CheckoutUserError> +} + +/** Return type for `checkoutLineItemsUpdate` mutation. */ +export type CheckoutLineItemsUpdatePayload = { + __typename?: 'CheckoutLineItemsUpdatePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutShippingAddressUpdate` mutation. */ +export type CheckoutShippingAddressUpdatePayload = { + __typename?: 'CheckoutShippingAddressUpdatePayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutShippingAddressUpdateV2` mutation. */ +export type CheckoutShippingAddressUpdateV2Payload = { + __typename?: 'CheckoutShippingAddressUpdateV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutShippingLineUpdate` mutation. */ +export type CheckoutShippingLineUpdatePayload = { + __typename?: 'CheckoutShippingLineUpdatePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Represents an error that happens during execution of a checkout mutation. */ +export type CheckoutUserError = DisplayableError & { + __typename?: 'CheckoutUserError' + /** Error code to uniquely identify the error. */ + code?: Maybe<CheckoutErrorCode> + /** Path to the input field which caused the error. */ + field?: Maybe<Array<Scalars['String']>> + /** The error message. */ + message: Scalars['String'] +} + +/** A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. */ +export type Collection = Node & { + __typename?: 'Collection' + /** Stripped description of the collection, single line with HTML tags removed. */ + description: Scalars['String'] + /** The description of the collection, complete with HTML formatting. */ + descriptionHtml: Scalars['HTML'] + /** + * A human-friendly unique string for the collection automatically generated from its title. + * Limit of 255 characters. + */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** Image associated with the collection. */ + image?: Maybe<Image> + /** List of products in the collection. */ + products: ProductConnection + /** The collection’s name. Limit of 255 characters. */ + title: Scalars['String'] + /** The date and time when the collection was last modified. */ + updatedAt: Scalars['DateTime'] +} + +/** A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. */ +export type CollectionDescriptionArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. */ +export type CollectionImageArgs = { + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> +} + +/** A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. */ +export type CollectionProductsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductCollectionSortKeys> +} + +/** An auto-generated type for paginating through multiple Collections. */ +export type CollectionConnection = { + __typename?: 'CollectionConnection' + /** A list of edges. */ + edges: Array<CollectionEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Collection and a cursor during pagination. */ +export type CollectionEdge = { + __typename?: 'CollectionEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of CollectionEdge. */ + node: Collection +} + +/** The set of valid sort keys for the Collection query. */ +export enum CollectionSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `updated_at` value. */ + UpdatedAt = 'UPDATED_AT', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** A comment on an article. */ +export type Comment = Node & { + __typename?: 'Comment' + /** The comment’s author. */ + author: CommentAuthor + /** Stripped content of the comment, single line with HTML tags removed. */ + content: Scalars['String'] + /** The content of the comment, complete with HTML formatting. */ + contentHtml: Scalars['HTML'] + /** Globally unique identifier. */ + id: Scalars['ID'] +} + +/** A comment on an article. */ +export type CommentContentArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** The author of a comment. */ +export type CommentAuthor = { + __typename?: 'CommentAuthor' + /** The author's email. */ + email: Scalars['String'] + /** The author’s name. */ + name: Scalars['String'] +} + +/** An auto-generated type for paginating through multiple Comments. */ +export type CommentConnection = { + __typename?: 'CommentConnection' + /** A list of edges. */ + edges: Array<CommentEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Comment and a cursor during pagination. */ +export type CommentEdge = { + __typename?: 'CommentEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of CommentEdge. */ + node: Comment +} + +/** ISO 3166-1 alpha-2 country codes with some differences. */ +export enum CountryCode { + /** Afghanistan. */ + Af = 'AF', + /** Åland Islands. */ + Ax = 'AX', + /** Albania. */ + Al = 'AL', + /** Algeria. */ + Dz = 'DZ', + /** Andorra. */ + Ad = 'AD', + /** Angola. */ + Ao = 'AO', + /** Anguilla. */ + Ai = 'AI', + /** Antigua & Barbuda. */ + Ag = 'AG', + /** Argentina. */ + Ar = 'AR', + /** Armenia. */ + Am = 'AM', + /** Aruba. */ + Aw = 'AW', + /** Australia. */ + Au = 'AU', + /** Austria. */ + At = 'AT', + /** Azerbaijan. */ + Az = 'AZ', + /** Bahamas. */ + Bs = 'BS', + /** Bahrain. */ + Bh = 'BH', + /** Bangladesh. */ + Bd = 'BD', + /** Barbados. */ + Bb = 'BB', + /** Belarus. */ + By = 'BY', + /** Belgium. */ + Be = 'BE', + /** Belize. */ + Bz = 'BZ', + /** Benin. */ + Bj = 'BJ', + /** Bermuda. */ + Bm = 'BM', + /** Bhutan. */ + Bt = 'BT', + /** Bolivia. */ + Bo = 'BO', + /** Bosnia & Herzegovina. */ + Ba = 'BA', + /** Botswana. */ + Bw = 'BW', + /** Bouvet Island. */ + Bv = 'BV', + /** Brazil. */ + Br = 'BR', + /** British Indian Ocean Territory. */ + Io = 'IO', + /** Brunei. */ + Bn = 'BN', + /** Bulgaria. */ + Bg = 'BG', + /** Burkina Faso. */ + Bf = 'BF', + /** Burundi. */ + Bi = 'BI', + /** Cambodia. */ + Kh = 'KH', + /** Canada. */ + Ca = 'CA', + /** Cape Verde. */ + Cv = 'CV', + /** Caribbean Netherlands. */ + Bq = 'BQ', + /** Cayman Islands. */ + Ky = 'KY', + /** Central African Republic. */ + Cf = 'CF', + /** Chad. */ + Td = 'TD', + /** Chile. */ + Cl = 'CL', + /** China. */ + Cn = 'CN', + /** Christmas Island. */ + Cx = 'CX', + /** Cocos (Keeling) Islands. */ + Cc = 'CC', + /** Colombia. */ + Co = 'CO', + /** Comoros. */ + Km = 'KM', + /** Congo - Brazzaville. */ + Cg = 'CG', + /** Congo - Kinshasa. */ + Cd = 'CD', + /** Cook Islands. */ + Ck = 'CK', + /** Costa Rica. */ + Cr = 'CR', + /** Croatia. */ + Hr = 'HR', + /** Cuba. */ + Cu = 'CU', + /** Curaçao. */ + Cw = 'CW', + /** Cyprus. */ + Cy = 'CY', + /** Czechia. */ + Cz = 'CZ', + /** Côte d’Ivoire. */ + Ci = 'CI', + /** Denmark. */ + Dk = 'DK', + /** Djibouti. */ + Dj = 'DJ', + /** Dominica. */ + Dm = 'DM', + /** Dominican Republic. */ + Do = 'DO', + /** Ecuador. */ + Ec = 'EC', + /** Egypt. */ + Eg = 'EG', + /** El Salvador. */ + Sv = 'SV', + /** Equatorial Guinea. */ + Gq = 'GQ', + /** Eritrea. */ + Er = 'ER', + /** Estonia. */ + Ee = 'EE', + /** Eswatini. */ + Sz = 'SZ', + /** Ethiopia. */ + Et = 'ET', + /** Falkland Islands. */ + Fk = 'FK', + /** Faroe Islands. */ + Fo = 'FO', + /** Fiji. */ + Fj = 'FJ', + /** Finland. */ + Fi = 'FI', + /** France. */ + Fr = 'FR', + /** French Guiana. */ + Gf = 'GF', + /** French Polynesia. */ + Pf = 'PF', + /** French Southern Territories. */ + Tf = 'TF', + /** Gabon. */ + Ga = 'GA', + /** Gambia. */ + Gm = 'GM', + /** Georgia. */ + Ge = 'GE', + /** Germany. */ + De = 'DE', + /** Ghana. */ + Gh = 'GH', + /** Gibraltar. */ + Gi = 'GI', + /** Greece. */ + Gr = 'GR', + /** Greenland. */ + Gl = 'GL', + /** Grenada. */ + Gd = 'GD', + /** Guadeloupe. */ + Gp = 'GP', + /** Guatemala. */ + Gt = 'GT', + /** Guernsey. */ + Gg = 'GG', + /** Guinea. */ + Gn = 'GN', + /** Guinea-Bissau. */ + Gw = 'GW', + /** Guyana. */ + Gy = 'GY', + /** Haiti. */ + Ht = 'HT', + /** Heard & McDonald Islands. */ + Hm = 'HM', + /** Vatican City. */ + Va = 'VA', + /** Honduras. */ + Hn = 'HN', + /** Hong Kong SAR. */ + Hk = 'HK', + /** Hungary. */ + Hu = 'HU', + /** Iceland. */ + Is = 'IS', + /** India. */ + In = 'IN', + /** Indonesia. */ + Id = 'ID', + /** Iran. */ + Ir = 'IR', + /** Iraq. */ + Iq = 'IQ', + /** Ireland. */ + Ie = 'IE', + /** Isle of Man. */ + Im = 'IM', + /** Israel. */ + Il = 'IL', + /** Italy. */ + It = 'IT', + /** Jamaica. */ + Jm = 'JM', + /** Japan. */ + Jp = 'JP', + /** Jersey. */ + Je = 'JE', + /** Jordan. */ + Jo = 'JO', + /** Kazakhstan. */ + Kz = 'KZ', + /** Kenya. */ + Ke = 'KE', + /** Kiribati. */ + Ki = 'KI', + /** North Korea. */ + Kp = 'KP', + /** Kosovo. */ + Xk = 'XK', + /** Kuwait. */ + Kw = 'KW', + /** Kyrgyzstan. */ + Kg = 'KG', + /** Laos. */ + La = 'LA', + /** Latvia. */ + Lv = 'LV', + /** Lebanon. */ + Lb = 'LB', + /** Lesotho. */ + Ls = 'LS', + /** Liberia. */ + Lr = 'LR', + /** Libya. */ + Ly = 'LY', + /** Liechtenstein. */ + Li = 'LI', + /** Lithuania. */ + Lt = 'LT', + /** Luxembourg. */ + Lu = 'LU', + /** Macao SAR. */ + Mo = 'MO', + /** Madagascar. */ + Mg = 'MG', + /** Malawi. */ + Mw = 'MW', + /** Malaysia. */ + My = 'MY', + /** Maldives. */ + Mv = 'MV', + /** Mali. */ + Ml = 'ML', + /** Malta. */ + Mt = 'MT', + /** Martinique. */ + Mq = 'MQ', + /** Mauritania. */ + Mr = 'MR', + /** Mauritius. */ + Mu = 'MU', + /** Mayotte. */ + Yt = 'YT', + /** Mexico. */ + Mx = 'MX', + /** Moldova. */ + Md = 'MD', + /** Monaco. */ + Mc = 'MC', + /** Mongolia. */ + Mn = 'MN', + /** Montenegro. */ + Me = 'ME', + /** Montserrat. */ + Ms = 'MS', + /** Morocco. */ + Ma = 'MA', + /** Mozambique. */ + Mz = 'MZ', + /** Myanmar (Burma). */ + Mm = 'MM', + /** Namibia. */ + Na = 'NA', + /** Nauru. */ + Nr = 'NR', + /** Nepal. */ + Np = 'NP', + /** Netherlands. */ + Nl = 'NL', + /** Netherlands Antilles. */ + An = 'AN', + /** New Caledonia. */ + Nc = 'NC', + /** New Zealand. */ + Nz = 'NZ', + /** Nicaragua. */ + Ni = 'NI', + /** Niger. */ + Ne = 'NE', + /** Nigeria. */ + Ng = 'NG', + /** Niue. */ + Nu = 'NU', + /** Norfolk Island. */ + Nf = 'NF', + /** North Macedonia. */ + Mk = 'MK', + /** Norway. */ + No = 'NO', + /** Oman. */ + Om = 'OM', + /** Pakistan. */ + Pk = 'PK', + /** Palestinian Territories. */ + Ps = 'PS', + /** Panama. */ + Pa = 'PA', + /** Papua New Guinea. */ + Pg = 'PG', + /** Paraguay. */ + Py = 'PY', + /** Peru. */ + Pe = 'PE', + /** Philippines. */ + Ph = 'PH', + /** Pitcairn Islands. */ + Pn = 'PN', + /** Poland. */ + Pl = 'PL', + /** Portugal. */ + Pt = 'PT', + /** Qatar. */ + Qa = 'QA', + /** Cameroon. */ + Cm = 'CM', + /** Réunion. */ + Re = 'RE', + /** Romania. */ + Ro = 'RO', + /** Russia. */ + Ru = 'RU', + /** Rwanda. */ + Rw = 'RW', + /** St. Barthélemy. */ + Bl = 'BL', + /** St. Helena. */ + Sh = 'SH', + /** St. Kitts & Nevis. */ + Kn = 'KN', + /** St. Lucia. */ + Lc = 'LC', + /** St. Martin. */ + Mf = 'MF', + /** St. Pierre & Miquelon. */ + Pm = 'PM', + /** Samoa. */ + Ws = 'WS', + /** San Marino. */ + Sm = 'SM', + /** São Tomé & Príncipe. */ + St = 'ST', + /** Saudi Arabia. */ + Sa = 'SA', + /** Senegal. */ + Sn = 'SN', + /** Serbia. */ + Rs = 'RS', + /** Seychelles. */ + Sc = 'SC', + /** Sierra Leone. */ + Sl = 'SL', + /** Singapore. */ + Sg = 'SG', + /** Sint Maarten. */ + Sx = 'SX', + /** Slovakia. */ + Sk = 'SK', + /** Slovenia. */ + Si = 'SI', + /** Solomon Islands. */ + Sb = 'SB', + /** Somalia. */ + So = 'SO', + /** South Africa. */ + Za = 'ZA', + /** South Georgia & South Sandwich Islands. */ + Gs = 'GS', + /** South Korea. */ + Kr = 'KR', + /** South Sudan. */ + Ss = 'SS', + /** Spain. */ + Es = 'ES', + /** Sri Lanka. */ + Lk = 'LK', + /** St. Vincent & Grenadines. */ + Vc = 'VC', + /** Sudan. */ + Sd = 'SD', + /** Suriname. */ + Sr = 'SR', + /** Svalbard & Jan Mayen. */ + Sj = 'SJ', + /** Sweden. */ + Se = 'SE', + /** Switzerland. */ + Ch = 'CH', + /** Syria. */ + Sy = 'SY', + /** Taiwan. */ + Tw = 'TW', + /** Tajikistan. */ + Tj = 'TJ', + /** Tanzania. */ + Tz = 'TZ', + /** Thailand. */ + Th = 'TH', + /** Timor-Leste. */ + Tl = 'TL', + /** Togo. */ + Tg = 'TG', + /** Tokelau. */ + Tk = 'TK', + /** Tonga. */ + To = 'TO', + /** Trinidad & Tobago. */ + Tt = 'TT', + /** Tunisia. */ + Tn = 'TN', + /** Turkey. */ + Tr = 'TR', + /** Turkmenistan. */ + Tm = 'TM', + /** Turks & Caicos Islands. */ + Tc = 'TC', + /** Tuvalu. */ + Tv = 'TV', + /** Uganda. */ + Ug = 'UG', + /** Ukraine. */ + Ua = 'UA', + /** United Arab Emirates. */ + Ae = 'AE', + /** United Kingdom. */ + Gb = 'GB', + /** United States. */ + Us = 'US', + /** U.S. Outlying Islands. */ + Um = 'UM', + /** Uruguay. */ + Uy = 'UY', + /** Uzbekistan. */ + Uz = 'UZ', + /** Vanuatu. */ + Vu = 'VU', + /** Venezuela. */ + Ve = 'VE', + /** Vietnam. */ + Vn = 'VN', + /** British Virgin Islands. */ + Vg = 'VG', + /** Wallis & Futuna. */ + Wf = 'WF', + /** Western Sahara. */ + Eh = 'EH', + /** Yemen. */ + Ye = 'YE', + /** Zambia. */ + Zm = 'ZM', + /** Zimbabwe. */ + Zw = 'ZW', +} + +/** Credit card information used for a payment. */ +export type CreditCard = { + __typename?: 'CreditCard' + /** The brand of the credit card. */ + brand?: Maybe<Scalars['String']> + /** The expiry month of the credit card. */ + expiryMonth?: Maybe<Scalars['Int']> + /** The expiry year of the credit card. */ + expiryYear?: Maybe<Scalars['Int']> + /** The credit card's BIN number. */ + firstDigits?: Maybe<Scalars['String']> + /** The first name of the card holder. */ + firstName?: Maybe<Scalars['String']> + /** The last 4 digits of the credit card. */ + lastDigits?: Maybe<Scalars['String']> + /** The last name of the card holder. */ + lastName?: Maybe<Scalars['String']> + /** The masked credit card number with only the last 4 digits displayed. */ + maskedNumber?: Maybe<Scalars['String']> +} + +/** + * Specifies the fields required to complete a checkout with + * a Shopify vaulted credit card payment. + */ +export type CreditCardPaymentInput = { + /** The amount of the payment. */ + amount: Scalars['Money'] + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** The ID returned by Shopify's Card Vault. */ + vaultId: Scalars['String'] + /** Executes the payment in test mode if possible. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> +} + +/** + * Specifies the fields required to complete a checkout with + * a Shopify vaulted credit card payment. + */ +export type CreditCardPaymentInputV2 = { + /** The amount and currency of the payment. */ + paymentAmount: MoneyInput + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** The ID returned by Shopify's Card Vault. */ + vaultId: Scalars['String'] + /** Executes the payment in test mode if possible. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> +} + +/** The part of the image that should remain after cropping. */ +export enum CropRegion { + /** Keep the center of the image. */ + Center = 'CENTER', + /** Keep the top of the image. */ + Top = 'TOP', + /** Keep the bottom of the image. */ + Bottom = 'BOTTOM', + /** Keep the left of the image. */ + Left = 'LEFT', + /** Keep the right of the image. */ + Right = 'RIGHT', +} + +/** Currency codes. */ +export enum CurrencyCode { + /** United States Dollars (USD). */ + Usd = 'USD', + /** Euro (EUR). */ + Eur = 'EUR', + /** United Kingdom Pounds (GBP). */ + Gbp = 'GBP', + /** Canadian Dollars (CAD). */ + Cad = 'CAD', + /** Afghan Afghani (AFN). */ + Afn = 'AFN', + /** Albanian Lek (ALL). */ + All = 'ALL', + /** Algerian Dinar (DZD). */ + Dzd = 'DZD', + /** Angolan Kwanza (AOA). */ + Aoa = 'AOA', + /** Argentine Pesos (ARS). */ + Ars = 'ARS', + /** Armenian Dram (AMD). */ + Amd = 'AMD', + /** Aruban Florin (AWG). */ + Awg = 'AWG', + /** Australian Dollars (AUD). */ + Aud = 'AUD', + /** Barbadian Dollar (BBD). */ + Bbd = 'BBD', + /** Azerbaijani Manat (AZN). */ + Azn = 'AZN', + /** Bangladesh Taka (BDT). */ + Bdt = 'BDT', + /** Bahamian Dollar (BSD). */ + Bsd = 'BSD', + /** Bahraini Dinar (BHD). */ + Bhd = 'BHD', + /** Burundian Franc (BIF). */ + Bif = 'BIF', + /** Belarusian Ruble (BYN). */ + Byn = 'BYN', + /** Belarusian Ruble (BYR). */ + Byr = 'BYR', + /** Belize Dollar (BZD). */ + Bzd = 'BZD', + /** Bermudian Dollar (BMD). */ + Bmd = 'BMD', + /** Bhutanese Ngultrum (BTN). */ + Btn = 'BTN', + /** Bosnia and Herzegovina Convertible Mark (BAM). */ + Bam = 'BAM', + /** Brazilian Real (BRL). */ + Brl = 'BRL', + /** Bolivian Boliviano (BOB). */ + Bob = 'BOB', + /** Botswana Pula (BWP). */ + Bwp = 'BWP', + /** Brunei Dollar (BND). */ + Bnd = 'BND', + /** Bulgarian Lev (BGN). */ + Bgn = 'BGN', + /** Burmese Kyat (MMK). */ + Mmk = 'MMK', + /** Cambodian Riel. */ + Khr = 'KHR', + /** Cape Verdean escudo (CVE). */ + Cve = 'CVE', + /** Cayman Dollars (KYD). */ + Kyd = 'KYD', + /** Central African CFA Franc (XAF). */ + Xaf = 'XAF', + /** Chilean Peso (CLP). */ + Clp = 'CLP', + /** Chinese Yuan Renminbi (CNY). */ + Cny = 'CNY', + /** Colombian Peso (COP). */ + Cop = 'COP', + /** Comorian Franc (KMF). */ + Kmf = 'KMF', + /** Congolese franc (CDF). */ + Cdf = 'CDF', + /** Costa Rican Colones (CRC). */ + Crc = 'CRC', + /** Croatian Kuna (HRK). */ + Hrk = 'HRK', + /** Czech Koruny (CZK). */ + Czk = 'CZK', + /** Danish Kroner (DKK). */ + Dkk = 'DKK', + /** Djiboutian Franc (DJF). */ + Djf = 'DJF', + /** Dominican Peso (DOP). */ + Dop = 'DOP', + /** East Caribbean Dollar (XCD). */ + Xcd = 'XCD', + /** Egyptian Pound (EGP). */ + Egp = 'EGP', + /** Eritrean Nakfa (ERN). */ + Ern = 'ERN', + /** Ethiopian Birr (ETB). */ + Etb = 'ETB', + /** Falkland Islands Pounds (FKP). */ + Fkp = 'FKP', + /** CFP Franc (XPF). */ + Xpf = 'XPF', + /** Fijian Dollars (FJD). */ + Fjd = 'FJD', + /** Gibraltar Pounds (GIP). */ + Gip = 'GIP', + /** Gambian Dalasi (GMD). */ + Gmd = 'GMD', + /** Ghanaian Cedi (GHS). */ + Ghs = 'GHS', + /** Guatemalan Quetzal (GTQ). */ + Gtq = 'GTQ', + /** Guyanese Dollar (GYD). */ + Gyd = 'GYD', + /** Georgian Lari (GEL). */ + Gel = 'GEL', + /** Guinean Franc (GNF). */ + Gnf = 'GNF', + /** Haitian Gourde (HTG). */ + Htg = 'HTG', + /** Honduran Lempira (HNL). */ + Hnl = 'HNL', + /** Hong Kong Dollars (HKD). */ + Hkd = 'HKD', + /** Hungarian Forint (HUF). */ + Huf = 'HUF', + /** Icelandic Kronur (ISK). */ + Isk = 'ISK', + /** Indian Rupees (INR). */ + Inr = 'INR', + /** Indonesian Rupiah (IDR). */ + Idr = 'IDR', + /** Israeli New Shekel (NIS). */ + Ils = 'ILS', + /** Iranian Rial (IRR). */ + Irr = 'IRR', + /** Iraqi Dinar (IQD). */ + Iqd = 'IQD', + /** Jamaican Dollars (JMD). */ + Jmd = 'JMD', + /** Japanese Yen (JPY). */ + Jpy = 'JPY', + /** Jersey Pound. */ + Jep = 'JEP', + /** Jordanian Dinar (JOD). */ + Jod = 'JOD', + /** Kazakhstani Tenge (KZT). */ + Kzt = 'KZT', + /** Kenyan Shilling (KES). */ + Kes = 'KES', + /** Kiribati Dollar (KID). */ + Kid = 'KID', + /** Kuwaiti Dinar (KWD). */ + Kwd = 'KWD', + /** Kyrgyzstani Som (KGS). */ + Kgs = 'KGS', + /** Laotian Kip (LAK). */ + Lak = 'LAK', + /** Latvian Lati (LVL). */ + Lvl = 'LVL', + /** Lebanese Pounds (LBP). */ + Lbp = 'LBP', + /** Lesotho Loti (LSL). */ + Lsl = 'LSL', + /** Liberian Dollar (LRD). */ + Lrd = 'LRD', + /** Libyan Dinar (LYD). */ + Lyd = 'LYD', + /** Lithuanian Litai (LTL). */ + Ltl = 'LTL', + /** Malagasy Ariary (MGA). */ + Mga = 'MGA', + /** Macedonia Denar (MKD). */ + Mkd = 'MKD', + /** Macanese Pataca (MOP). */ + Mop = 'MOP', + /** Malawian Kwacha (MWK). */ + Mwk = 'MWK', + /** Maldivian Rufiyaa (MVR). */ + Mvr = 'MVR', + /** Mauritanian Ouguiya (MRU). */ + Mru = 'MRU', + /** Mexican Pesos (MXN). */ + Mxn = 'MXN', + /** Malaysian Ringgits (MYR). */ + Myr = 'MYR', + /** Mauritian Rupee (MUR). */ + Mur = 'MUR', + /** Moldovan Leu (MDL). */ + Mdl = 'MDL', + /** Moroccan Dirham. */ + Mad = 'MAD', + /** Mongolian Tugrik. */ + Mnt = 'MNT', + /** Mozambican Metical. */ + Mzn = 'MZN', + /** Namibian Dollar. */ + Nad = 'NAD', + /** Nepalese Rupee (NPR). */ + Npr = 'NPR', + /** Netherlands Antillean Guilder. */ + Ang = 'ANG', + /** New Zealand Dollars (NZD). */ + Nzd = 'NZD', + /** Nicaraguan Córdoba (NIO). */ + Nio = 'NIO', + /** Nigerian Naira (NGN). */ + Ngn = 'NGN', + /** Norwegian Kroner (NOK). */ + Nok = 'NOK', + /** Omani Rial (OMR). */ + Omr = 'OMR', + /** Panamian Balboa (PAB). */ + Pab = 'PAB', + /** Pakistani Rupee (PKR). */ + Pkr = 'PKR', + /** Papua New Guinean Kina (PGK). */ + Pgk = 'PGK', + /** Paraguayan Guarani (PYG). */ + Pyg = 'PYG', + /** Peruvian Nuevo Sol (PEN). */ + Pen = 'PEN', + /** Philippine Peso (PHP). */ + Php = 'PHP', + /** Polish Zlotych (PLN). */ + Pln = 'PLN', + /** Qatari Rial (QAR). */ + Qar = 'QAR', + /** Romanian Lei (RON). */ + Ron = 'RON', + /** Russian Rubles (RUB). */ + Rub = 'RUB', + /** Rwandan Franc (RWF). */ + Rwf = 'RWF', + /** Samoan Tala (WST). */ + Wst = 'WST', + /** Saint Helena Pounds (SHP). */ + Shp = 'SHP', + /** Saudi Riyal (SAR). */ + Sar = 'SAR', + /** Sao Tome And Principe Dobra (STD). */ + Std = 'STD', + /** Serbian dinar (RSD). */ + Rsd = 'RSD', + /** Seychellois Rupee (SCR). */ + Scr = 'SCR', + /** Sierra Leonean Leone (SLL). */ + Sll = 'SLL', + /** Singapore Dollars (SGD). */ + Sgd = 'SGD', + /** Sudanese Pound (SDG). */ + Sdg = 'SDG', + /** Somali Shilling (SOS). */ + Sos = 'SOS', + /** Syrian Pound (SYP). */ + Syp = 'SYP', + /** South African Rand (ZAR). */ + Zar = 'ZAR', + /** South Korean Won (KRW). */ + Krw = 'KRW', + /** South Sudanese Pound (SSP). */ + Ssp = 'SSP', + /** Solomon Islands Dollar (SBD). */ + Sbd = 'SBD', + /** Sri Lankan Rupees (LKR). */ + Lkr = 'LKR', + /** Surinamese Dollar (SRD). */ + Srd = 'SRD', + /** Swazi Lilangeni (SZL). */ + Szl = 'SZL', + /** Swedish Kronor (SEK). */ + Sek = 'SEK', + /** Swiss Francs (CHF). */ + Chf = 'CHF', + /** Taiwan Dollars (TWD). */ + Twd = 'TWD', + /** Thai baht (THB). */ + Thb = 'THB', + /** Tajikistani Somoni (TJS). */ + Tjs = 'TJS', + /** Tanzanian Shilling (TZS). */ + Tzs = 'TZS', + /** Tongan Pa'anga (TOP). */ + Top = 'TOP', + /** Trinidad and Tobago Dollars (TTD). */ + Ttd = 'TTD', + /** Tunisian Dinar (TND). */ + Tnd = 'TND', + /** Turkish Lira (TRY). */ + Try = 'TRY', + /** Turkmenistani Manat (TMT). */ + Tmt = 'TMT', + /** Ugandan Shilling (UGX). */ + Ugx = 'UGX', + /** Ukrainian Hryvnia (UAH). */ + Uah = 'UAH', + /** United Arab Emirates Dirham (AED). */ + Aed = 'AED', + /** Uruguayan Pesos (UYU). */ + Uyu = 'UYU', + /** Uzbekistan som (UZS). */ + Uzs = 'UZS', + /** Vanuatu Vatu (VUV). */ + Vuv = 'VUV', + /** Venezuelan Bolivares (VEF). */ + Vef = 'VEF', + /** Venezuelan Bolivares (VES). */ + Ves = 'VES', + /** Vietnamese đồng (VND). */ + Vnd = 'VND', + /** West African CFA franc (XOF). */ + Xof = 'XOF', + /** Yemeni Rial (YER). */ + Yer = 'YER', + /** Zambian Kwacha (ZMW). */ + Zmw = 'ZMW', +} + +/** A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. */ +export type Customer = { + __typename?: 'Customer' + /** Indicates whether the customer has consented to be sent marketing material via email. */ + acceptsMarketing: Scalars['Boolean'] + /** A list of addresses for the customer. */ + addresses: MailingAddressConnection + /** The date and time when the customer was created. */ + createdAt: Scalars['DateTime'] + /** The customer’s default address. */ + defaultAddress?: Maybe<MailingAddress> + /** The customer’s name, email or phone number. */ + displayName: Scalars['String'] + /** The customer’s email address. */ + email?: Maybe<Scalars['String']> + /** The customer’s first name. */ + firstName?: Maybe<Scalars['String']> + /** A unique identifier for the customer. */ + id: Scalars['ID'] + /** The customer's most recently updated, incomplete checkout. */ + lastIncompleteCheckout?: Maybe<Checkout> + /** The customer’s last name. */ + lastName?: Maybe<Scalars['String']> + /** The orders associated with the customer. */ + orders: OrderConnection + /** The customer’s phone number. */ + phone?: Maybe<Scalars['String']> + /** + * A comma separated list of tags that have been added to the customer. + * Additional access scope required: unauthenticated_read_customer_tags. + */ + tags: Array<Scalars['String']> + /** The date and time when the customer information was updated. */ + updatedAt: Scalars['DateTime'] +} + +/** A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. */ +export type CustomerAddressesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. */ +export type CustomerOrdersArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<OrderSortKeys> + query?: Maybe<Scalars['String']> +} + +/** A CustomerAccessToken represents the unique token required to make modifications to the customer object. */ +export type CustomerAccessToken = { + __typename?: 'CustomerAccessToken' + /** The customer’s access token. */ + accessToken: Scalars['String'] + /** The date and time when the customer access token expires. */ + expiresAt: Scalars['DateTime'] +} + +/** Specifies the input fields required to create a customer access token. */ +export type CustomerAccessTokenCreateInput = { + /** The email associated to the customer. */ + email: Scalars['String'] + /** The login password to be used by the customer. */ + password: Scalars['String'] +} + +/** Return type for `customerAccessTokenCreate` mutation. */ +export type CustomerAccessTokenCreatePayload = { + __typename?: 'CustomerAccessTokenCreatePayload' + /** The newly created customer access token object. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerAccessTokenCreateWithMultipass` mutation. */ +export type CustomerAccessTokenCreateWithMultipassPayload = { + __typename?: 'CustomerAccessTokenCreateWithMultipassPayload' + /** An access token object associated with the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> +} + +/** Return type for `customerAccessTokenDelete` mutation. */ +export type CustomerAccessTokenDeletePayload = { + __typename?: 'CustomerAccessTokenDeletePayload' + /** The destroyed access token. */ + deletedAccessToken?: Maybe<Scalars['String']> + /** ID of the destroyed customer access token. */ + deletedCustomerAccessTokenId?: Maybe<Scalars['String']> + /** List of errors that occurred executing the mutation. */ + userErrors: Array<UserError> +} + +/** Return type for `customerAccessTokenRenew` mutation. */ +export type CustomerAccessTokenRenewPayload = { + __typename?: 'CustomerAccessTokenRenewPayload' + /** The renewed customer access token object. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + userErrors: Array<UserError> +} + +/** Return type for `customerActivateByUrl` mutation. */ +export type CustomerActivateByUrlPayload = { + __typename?: 'CustomerActivateByUrlPayload' + /** The customer that was activated. */ + customer?: Maybe<Customer> + /** A new customer access token for the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> +} + +/** Specifies the input fields required to activate a customer. */ +export type CustomerActivateInput = { + /** The activation token required to activate the customer. */ + activationToken: Scalars['String'] + /** New password that will be set during activation. */ + password: Scalars['String'] +} + +/** Return type for `customerActivate` mutation. */ +export type CustomerActivatePayload = { + __typename?: 'CustomerActivatePayload' + /** The customer object. */ + customer?: Maybe<Customer> + /** A newly created customer access token object for the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerAddressCreate` mutation. */ +export type CustomerAddressCreatePayload = { + __typename?: 'CustomerAddressCreatePayload' + /** The new customer address object. */ + customerAddress?: Maybe<MailingAddress> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerAddressDelete` mutation. */ +export type CustomerAddressDeletePayload = { + __typename?: 'CustomerAddressDeletePayload' + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** ID of the deleted customer address. */ + deletedCustomerAddressId?: Maybe<Scalars['String']> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerAddressUpdate` mutation. */ +export type CustomerAddressUpdatePayload = { + __typename?: 'CustomerAddressUpdatePayload' + /** The customer’s updated mailing address. */ + customerAddress?: Maybe<MailingAddress> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to create a new customer. */ +export type CustomerCreateInput = { + /** The customer’s first name. */ + firstName?: Maybe<Scalars['String']> + /** The customer’s last name. */ + lastName?: Maybe<Scalars['String']> + /** The customer’s email. */ + email: Scalars['String'] + /** + * A unique phone number for the customer. + * + * Formatted using E.164 standard. For example, _+16135551111_. + */ + phone?: Maybe<Scalars['String']> + /** The login password used by the customer. */ + password: Scalars['String'] + /** Indicates whether the customer has consented to be sent marketing material via email. */ + acceptsMarketing?: Maybe<Scalars['Boolean']> +} + +/** Return type for `customerCreate` mutation. */ +export type CustomerCreatePayload = { + __typename?: 'CustomerCreatePayload' + /** The created customer object. */ + customer?: Maybe<Customer> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerDefaultAddressUpdate` mutation. */ +export type CustomerDefaultAddressUpdatePayload = { + __typename?: 'CustomerDefaultAddressUpdatePayload' + /** The updated customer object. */ + customer?: Maybe<Customer> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Possible error codes that could be returned by CustomerUserError. */ +export enum CustomerErrorCode { + /** Input value is blank. */ + Blank = 'BLANK', + /** Input value is invalid. */ + Invalid = 'INVALID', + /** Input value is already taken. */ + Taken = 'TAKEN', + /** Input value is too long. */ + TooLong = 'TOO_LONG', + /** Input value is too short. */ + TooShort = 'TOO_SHORT', + /** Unidentified customer. */ + UnidentifiedCustomer = 'UNIDENTIFIED_CUSTOMER', + /** Customer is disabled. */ + CustomerDisabled = 'CUSTOMER_DISABLED', + /** Input password starts or ends with whitespace. */ + PasswordStartsOrEndsWithWhitespace = 'PASSWORD_STARTS_OR_ENDS_WITH_WHITESPACE', + /** Input contains HTML tags. */ + ContainsHtmlTags = 'CONTAINS_HTML_TAGS', + /** Input contains URL. */ + ContainsUrl = 'CONTAINS_URL', + /** Invalid activation token. */ + TokenInvalid = 'TOKEN_INVALID', + /** Customer already enabled. */ + AlreadyEnabled = 'ALREADY_ENABLED', + /** Address does not exist. */ + NotFound = 'NOT_FOUND', + /** Input email contains an invalid domain name. */ + BadDomain = 'BAD_DOMAIN', + /** Multipass token is not valid. */ + InvalidMultipassRequest = 'INVALID_MULTIPASS_REQUEST', +} + +/** Return type for `customerRecover` mutation. */ +export type CustomerRecoverPayload = { + __typename?: 'CustomerRecoverPayload' + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerResetByUrl` mutation. */ +export type CustomerResetByUrlPayload = { + __typename?: 'CustomerResetByUrlPayload' + /** The customer object which was reset. */ + customer?: Maybe<Customer> + /** A newly created customer access token object for the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to reset a customer’s password. */ +export type CustomerResetInput = { + /** The reset token required to reset the customer’s password. */ + resetToken: Scalars['String'] + /** New password that will be set as part of the reset password process. */ + password: Scalars['String'] +} + +/** Return type for `customerReset` mutation. */ +export type CustomerResetPayload = { + __typename?: 'CustomerResetPayload' + /** The customer object which was reset. */ + customer?: Maybe<Customer> + /** A newly created customer access token object for the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to update the Customer information. */ +export type CustomerUpdateInput = { + /** The customer’s first name. */ + firstName?: Maybe<Scalars['String']> + /** The customer’s last name. */ + lastName?: Maybe<Scalars['String']> + /** The customer’s email. */ + email?: Maybe<Scalars['String']> + /** + * A unique phone number for the customer. + * + * Formatted using E.164 standard. For example, _+16135551111_. To remove the phone number, specify `null`. + */ + phone?: Maybe<Scalars['String']> + /** The login password used by the customer. */ + password?: Maybe<Scalars['String']> + /** Indicates whether the customer has consented to be sent marketing material via email. */ + acceptsMarketing?: Maybe<Scalars['Boolean']> +} + +/** Return type for `customerUpdate` mutation. */ +export type CustomerUpdatePayload = { + __typename?: 'CustomerUpdatePayload' + /** The updated customer object. */ + customer?: Maybe<Customer> + /** + * The newly created customer access token. If the customer's password is updated, all previous access tokens + * (including the one used to perform this mutation) become invalid, and a new token is generated. + */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Represents an error that happens during execution of a customer mutation. */ +export type CustomerUserError = DisplayableError & { + __typename?: 'CustomerUserError' + /** Error code to uniquely identify the error. */ + code?: Maybe<CustomerErrorCode> + /** Path to the input field which caused the error. */ + field?: Maybe<Array<Scalars['String']>> + /** The error message. */ + message: Scalars['String'] +} + +/** Digital wallet, such as Apple Pay, which can be used for accelerated checkouts. */ +export enum DigitalWallet { + /** Apple Pay. */ + ApplePay = 'APPLE_PAY', + /** Android Pay. */ + AndroidPay = 'ANDROID_PAY', + /** Google Pay. */ + GooglePay = 'GOOGLE_PAY', + /** Shopify Pay. */ + ShopifyPay = 'SHOPIFY_PAY', +} + +/** An amount discounting the line that has been allocated by a discount. */ +export type DiscountAllocation = { + __typename?: 'DiscountAllocation' + /** Amount of discount allocated. */ + allocatedAmount: MoneyV2 + /** The discount this allocated amount originated from. */ + discountApplication: DiscountApplication +} + +/** + * Discount applications capture the intentions of a discount source at + * the time of application. + */ +export type DiscountApplication = { + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The value of the discount application. */ + value: PricingValue +} + +/** The method by which the discount's value is allocated onto its entitled lines. */ +export enum DiscountApplicationAllocationMethod { + /** The value is spread across all entitled lines. */ + Across = 'ACROSS', + /** The value is applied onto every entitled line. */ + Each = 'EACH', + /** The value is specifically applied onto a particular line. */ + One = 'ONE', +} + +/** An auto-generated type for paginating through multiple DiscountApplications. */ +export type DiscountApplicationConnection = { + __typename?: 'DiscountApplicationConnection' + /** A list of edges. */ + edges: Array<DiscountApplicationEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one DiscountApplication and a cursor during pagination. */ +export type DiscountApplicationEdge = { + __typename?: 'DiscountApplicationEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of DiscountApplicationEdge. */ + node: DiscountApplication +} + +/** + * Which lines on the order that the discount is allocated over, of the type + * defined by the Discount Application's target_type. + */ +export enum DiscountApplicationTargetSelection { + /** The discount is allocated onto all the lines. */ + All = 'ALL', + /** The discount is allocated onto only the lines it is entitled for. */ + Entitled = 'ENTITLED', + /** The discount is allocated onto explicitly chosen lines. */ + Explicit = 'EXPLICIT', +} + +/** The type of line (i.e. line item or shipping line) on an order that the discount is applicable towards. */ +export enum DiscountApplicationTargetType { + /** The discount applies onto line items. */ + LineItem = 'LINE_ITEM', + /** The discount applies onto shipping lines. */ + ShippingLine = 'SHIPPING_LINE', +} + +/** + * Discount code applications capture the intentions of a discount code at + * the time that it is applied. + */ +export type DiscountCodeApplication = DiscountApplication & { + __typename?: 'DiscountCodeApplication' + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** Specifies whether the discount code was applied successfully. */ + applicable: Scalars['Boolean'] + /** The string identifying the discount code that was used at the time of application. */ + code: Scalars['String'] + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The value of the discount application. */ + value: PricingValue +} + +/** Represents an error in the input of a mutation. */ +export type DisplayableError = { + /** Path to the input field which caused the error. */ + field?: Maybe<Array<Scalars['String']>> + /** The error message. */ + message: Scalars['String'] +} + +/** Represents a web address. */ +export type Domain = { + __typename?: 'Domain' + /** The host name of the domain (eg: `example.com`). */ + host: Scalars['String'] + /** Whether SSL is enabled or not. */ + sslEnabled: Scalars['Boolean'] + /** The URL of the domain (eg: `https://example.com`). */ + url: Scalars['URL'] +} + +/** Represents a video hosted outside of Shopify. */ +export type ExternalVideo = Node & + Media & { + __typename?: 'ExternalVideo' + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** The URL. */ + embeddedUrl: Scalars['URL'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> + } + +/** Represents a single fulfillment in an order. */ +export type Fulfillment = { + __typename?: 'Fulfillment' + /** List of the fulfillment's line items. */ + fulfillmentLineItems: FulfillmentLineItemConnection + /** The name of the tracking company. */ + trackingCompany?: Maybe<Scalars['String']> + /** + * Tracking information associated with the fulfillment, + * such as the tracking number and tracking URL. + */ + trackingInfo: Array<FulfillmentTrackingInfo> +} + +/** Represents a single fulfillment in an order. */ +export type FulfillmentFulfillmentLineItemsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** Represents a single fulfillment in an order. */ +export type FulfillmentTrackingInfoArgs = { + first?: Maybe<Scalars['Int']> +} + +/** Represents a single line item in a fulfillment. There is at most one fulfillment line item for each order line item. */ +export type FulfillmentLineItem = { + __typename?: 'FulfillmentLineItem' + /** The associated order's line item. */ + lineItem: OrderLineItem + /** The amount fulfilled in this fulfillment. */ + quantity: Scalars['Int'] +} + +/** An auto-generated type for paginating through multiple FulfillmentLineItems. */ +export type FulfillmentLineItemConnection = { + __typename?: 'FulfillmentLineItemConnection' + /** A list of edges. */ + edges: Array<FulfillmentLineItemEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one FulfillmentLineItem and a cursor during pagination. */ +export type FulfillmentLineItemEdge = { + __typename?: 'FulfillmentLineItemEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of FulfillmentLineItemEdge. */ + node: FulfillmentLineItem +} + +/** Tracking information associated with the fulfillment. */ +export type FulfillmentTrackingInfo = { + __typename?: 'FulfillmentTrackingInfo' + /** The tracking number of the fulfillment. */ + number?: Maybe<Scalars['String']> + /** The URL to track the fulfillment. */ + url?: Maybe<Scalars['URL']> +} + +/** Represents information about the metafields associated to the specified resource. */ +export type HasMetafields = { + /** The metafield associated with the resource. */ + metafield?: Maybe<Metafield> + /** A paginated list of metafields associated with the resource. */ + metafields: MetafieldConnection +} + +/** Represents information about the metafields associated to the specified resource. */ +export type HasMetafieldsMetafieldArgs = { + namespace: Scalars['String'] + key: Scalars['String'] +} + +/** Represents information about the metafields associated to the specified resource. */ +export type HasMetafieldsMetafieldsArgs = { + namespace?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** Represents an image resource. */ +export type Image = { + __typename?: 'Image' + /** A word or phrase to share the nature or contents of an image. */ + altText?: Maybe<Scalars['String']> + /** The original height of the image in pixels. Returns `null` if the image is not hosted by Shopify. */ + height?: Maybe<Scalars['Int']> + /** A unique identifier for the image. */ + id?: Maybe<Scalars['ID']> + /** + * The location of the original image as a URL. + * + * If there are any existing transformations in the original source URL, they will remain and not be stripped. + */ + originalSrc: Scalars['URL'] + /** + * The location of the image as a URL. + * @deprecated Previously an image had a single `src` field. This could either return the original image + * location or a URL that contained transformations such as sizing or scale. + * + * These transformations were specified by arguments on the parent field. + * + * Now an image has two distinct URL fields: `originalSrc` and `transformedSrc`. + * + * * `originalSrc` - the original unmodified image URL + * * `transformedSrc` - the image URL with the specified transformations included + * + * To migrate to the new fields, image transformations should be moved from the parent field to `transformedSrc`. + * + * Before: + * ```graphql + * { + * shop { + * productImages(maxWidth: 200, scale: 2) { + * edges { + * node { + * src + * } + * } + * } + * } + * } + * ``` + * + * After: + * ```graphql + * { + * shop { + * productImages { + * edges { + * node { + * transformedSrc(maxWidth: 200, scale: 2) + * } + * } + * } + * } + * } + * ``` + * + */ + src: Scalars['URL'] + /** + * The location of the transformed image as a URL. + * + * All transformation arguments are considered "best-effort". If they can be applied to an image, they will be. + * Otherwise any transformations which an image type does not support will be ignored. + */ + transformedSrc: Scalars['URL'] + /** The original width of the image in pixels. Returns `null` if the image is not hosted by Shopify. */ + width?: Maybe<Scalars['Int']> +} + +/** Represents an image resource. */ +export type ImageTransformedSrcArgs = { + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> + preferredContentType?: Maybe<ImageContentType> +} + +/** An auto-generated type for paginating through multiple Images. */ +export type ImageConnection = { + __typename?: 'ImageConnection' + /** A list of edges. */ + edges: Array<ImageEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** List of supported image content types. */ +export enum ImageContentType { + /** A PNG image. */ + Png = 'PNG', + /** A JPG image. */ + Jpg = 'JPG', + /** A WEBP image. */ + Webp = 'WEBP', +} + +/** An auto-generated type which holds one Image and a cursor during pagination. */ +export type ImageEdge = { + __typename?: 'ImageEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ImageEdge. */ + node: Image +} + +/** Represents a mailing address for customers and shipping. */ +export type MailingAddress = Node & { + __typename?: 'MailingAddress' + /** The first line of the address. Typically the street address or PO Box number. */ + address1?: Maybe<Scalars['String']> + /** The second line of the address. Typically the number of the apartment, suite, or unit. */ + address2?: Maybe<Scalars['String']> + /** The name of the city, district, village, or town. */ + city?: Maybe<Scalars['String']> + /** The name of the customer's company or organization. */ + company?: Maybe<Scalars['String']> + /** The name of the country. */ + country?: Maybe<Scalars['String']> + /** + * The two-letter code for the country of the address. + * + * For example, US. + * @deprecated Use `countryCodeV2` instead + */ + countryCode?: Maybe<Scalars['String']> + /** + * The two-letter code for the country of the address. + * + * For example, US. + */ + countryCodeV2?: Maybe<CountryCode> + /** The first name of the customer. */ + firstName?: Maybe<Scalars['String']> + /** A formatted version of the address, customized by the provided arguments. */ + formatted: Array<Scalars['String']> + /** A comma-separated list of the values for city, province, and country. */ + formattedArea?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The last name of the customer. */ + lastName?: Maybe<Scalars['String']> + /** The latitude coordinate of the customer address. */ + latitude?: Maybe<Scalars['Float']> + /** The longitude coordinate of the customer address. */ + longitude?: Maybe<Scalars['Float']> + /** The full name of the customer, based on firstName and lastName. */ + name?: Maybe<Scalars['String']> + /** + * A unique phone number for the customer. + * + * Formatted using E.164 standard. For example, _+16135551111_. + */ + phone?: Maybe<Scalars['String']> + /** The region of the address, such as the province, state, or district. */ + province?: Maybe<Scalars['String']> + /** + * The two-letter code for the region. + * + * For example, ON. + */ + provinceCode?: Maybe<Scalars['String']> + /** The zip or postal code of the address. */ + zip?: Maybe<Scalars['String']> +} + +/** Represents a mailing address for customers and shipping. */ +export type MailingAddressFormattedArgs = { + withName?: Maybe<Scalars['Boolean']> + withCompany?: Maybe<Scalars['Boolean']> +} + +/** An auto-generated type for paginating through multiple MailingAddresses. */ +export type MailingAddressConnection = { + __typename?: 'MailingAddressConnection' + /** A list of edges. */ + edges: Array<MailingAddressEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one MailingAddress and a cursor during pagination. */ +export type MailingAddressEdge = { + __typename?: 'MailingAddressEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of MailingAddressEdge. */ + node: MailingAddress +} + +/** Specifies the fields accepted to create or update a mailing address. */ +export type MailingAddressInput = { + /** The first line of the address. Typically the street address or PO Box number. */ + address1?: Maybe<Scalars['String']> + /** The second line of the address. Typically the number of the apartment, suite, or unit. */ + address2?: Maybe<Scalars['String']> + /** The name of the city, district, village, or town. */ + city?: Maybe<Scalars['String']> + /** The name of the customer's company or organization. */ + company?: Maybe<Scalars['String']> + /** The name of the country. */ + country?: Maybe<Scalars['String']> + /** The first name of the customer. */ + firstName?: Maybe<Scalars['String']> + /** The last name of the customer. */ + lastName?: Maybe<Scalars['String']> + /** + * A unique phone number for the customer. + * + * Formatted using E.164 standard. For example, _+16135551111_. + */ + phone?: Maybe<Scalars['String']> + /** The region of the address, such as the province, state, or district. */ + province?: Maybe<Scalars['String']> + /** The zip or postal code of the address. */ + zip?: Maybe<Scalars['String']> +} + +/** Manual discount applications capture the intentions of a discount that was manually created. */ +export type ManualDiscountApplication = DiscountApplication & { + __typename?: 'ManualDiscountApplication' + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** The description of the application. */ + description?: Maybe<Scalars['String']> + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The title of the application. */ + title: Scalars['String'] + /** The value of the discount application. */ + value: PricingValue +} + +/** Represents a media interface. */ +export type Media = { + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> +} + +/** An auto-generated type for paginating through multiple Media. */ +export type MediaConnection = { + __typename?: 'MediaConnection' + /** A list of edges. */ + edges: Array<MediaEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** The possible content types for a media object. */ +export enum MediaContentType { + /** An externally hosted video. */ + ExternalVideo = 'EXTERNAL_VIDEO', + /** A Shopify hosted image. */ + Image = 'IMAGE', + /** A 3d model. */ + Model_3D = 'MODEL_3D', + /** A Shopify hosted video. */ + Video = 'VIDEO', +} + +/** An auto-generated type which holds one Media and a cursor during pagination. */ +export type MediaEdge = { + __typename?: 'MediaEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of MediaEdge. */ + node: Media +} + +/** Represents a Shopify hosted image. */ +export type MediaImage = Node & + Media & { + __typename?: 'MediaImage' + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The image for the media. */ + image?: Maybe<Image> + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> + } + +/** + * Metafields represent custom metadata attached to a resource. Metafields can be sorted into namespaces and are + * comprised of keys, values, and value types. + */ +export type Metafield = Node & { + __typename?: 'Metafield' + /** The date and time when the storefront metafield was created. */ + createdAt: Scalars['DateTime'] + /** The description of a metafield. */ + description?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The key name for a metafield. */ + key: Scalars['String'] + /** The namespace for a metafield. */ + namespace: Scalars['String'] + /** The parent object that the metafield belongs to. */ + parentResource: MetafieldParentResource + /** The date and time when the storefront metafield was updated. */ + updatedAt: Scalars['DateTime'] + /** The value of a metafield. */ + value: Scalars['String'] + /** Represents the metafield value type. */ + valueType: MetafieldValueType +} + +/** An auto-generated type for paginating through multiple Metafields. */ +export type MetafieldConnection = { + __typename?: 'MetafieldConnection' + /** A list of edges. */ + edges: Array<MetafieldEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Metafield and a cursor during pagination. */ +export type MetafieldEdge = { + __typename?: 'MetafieldEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of MetafieldEdge. */ + node: Metafield +} + +/** A resource that the metafield belongs to. */ +export type MetafieldParentResource = Product | ProductVariant + +/** Metafield value types. */ +export enum MetafieldValueType { + /** A string metafield. */ + String = 'STRING', + /** An integer metafield. */ + Integer = 'INTEGER', + /** A json string metafield. */ + JsonString = 'JSON_STRING', +} + +/** Represents a Shopify hosted 3D model. */ +export type Model3d = Node & + Media & { + __typename?: 'Model3d' + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> + /** The sources for a 3d model. */ + sources: Array<Model3dSource> + } + +/** Represents a source for a Shopify hosted 3d model. */ +export type Model3dSource = { + __typename?: 'Model3dSource' + /** The filesize of the 3d model. */ + filesize: Scalars['Int'] + /** The format of the 3d model. */ + format: Scalars['String'] + /** The MIME type of the 3d model. */ + mimeType: Scalars['String'] + /** The URL of the 3d model. */ + url: Scalars['String'] +} + +/** Specifies the fields for a monetary value with currency. */ +export type MoneyInput = { + /** Decimal money amount. */ + amount: Scalars['Decimal'] + /** Currency of the money. */ + currencyCode: CurrencyCode +} + +/** + * A monetary value with currency. + * + * To format currencies, combine this type's amount and currencyCode fields with your client's locale. + * + * For example, in JavaScript you could use Intl.NumberFormat: + * + * ```js + * new Intl.NumberFormat(locale, { + * style: 'currency', + * currency: currencyCode + * }).format(amount); + * ``` + * + * Other formatting libraries include: + * + * * iOS - [NumberFormatter](https://developer.apple.com/documentation/foundation/numberformatter) + * * Android - [NumberFormat](https://developer.android.com/reference/java/text/NumberFormat.html) + * * PHP - [NumberFormatter](http://php.net/manual/en/class.numberformatter.php) + * + * For a more general solution, the [Unicode CLDR number formatting database] is available with many implementations + * (such as [TwitterCldr](https://github.com/twitter/twitter-cldr-rb)). + */ +export type MoneyV2 = { + __typename?: 'MoneyV2' + /** Decimal money amount. */ + amount: Scalars['Decimal'] + /** Currency of the money. */ + currencyCode: CurrencyCode +} + +/** An auto-generated type for paginating through multiple MoneyV2s. */ +export type MoneyV2Connection = { + __typename?: 'MoneyV2Connection' + /** A list of edges. */ + edges: Array<MoneyV2Edge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one MoneyV2 and a cursor during pagination. */ +export type MoneyV2Edge = { + __typename?: 'MoneyV2Edge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of MoneyV2Edge. */ + node: MoneyV2 +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type Mutation = { + __typename?: 'Mutation' + /** + * Updates the attributes of a checkout. + * @deprecated Use `checkoutAttributesUpdateV2` instead + */ + checkoutAttributesUpdate?: Maybe<CheckoutAttributesUpdatePayload> + /** Updates the attributes of a checkout. */ + checkoutAttributesUpdateV2?: Maybe<CheckoutAttributesUpdateV2Payload> + /** Completes a checkout without providing payment information. You can use this mutation for free items or items whose purchase price is covered by a gift card. */ + checkoutCompleteFree?: Maybe<CheckoutCompleteFreePayload> + /** + * Completes a checkout using a credit card token from Shopify's Vault. + * @deprecated Use `checkoutCompleteWithCreditCardV2` instead + */ + checkoutCompleteWithCreditCard?: Maybe<CheckoutCompleteWithCreditCardPayload> + /** Completes a checkout using a credit card token from Shopify's card vault. Before you can complete checkouts using CheckoutCompleteWithCreditCardV2, you need to [_request payment processing_](https://help.shopify.com/api/guides/sales-channel-sdk/getting-started#request-payment-processing). */ + checkoutCompleteWithCreditCardV2?: Maybe<CheckoutCompleteWithCreditCardV2Payload> + /** + * Completes a checkout with a tokenized payment. + * @deprecated Use `checkoutCompleteWithTokenizedPaymentV2` instead + */ + checkoutCompleteWithTokenizedPayment?: Maybe<CheckoutCompleteWithTokenizedPaymentPayload> + /** + * Completes a checkout with a tokenized payment. + * @deprecated Use `checkoutCompleteWithTokenizedPaymentV3` instead + */ + checkoutCompleteWithTokenizedPaymentV2?: Maybe<CheckoutCompleteWithTokenizedPaymentV2Payload> + /** Completes a checkout with a tokenized payment. */ + checkoutCompleteWithTokenizedPaymentV3?: Maybe<CheckoutCompleteWithTokenizedPaymentV3Payload> + /** Creates a new checkout. */ + checkoutCreate?: Maybe<CheckoutCreatePayload> + /** + * Associates a customer to the checkout. + * @deprecated Use `checkoutCustomerAssociateV2` instead + */ + checkoutCustomerAssociate?: Maybe<CheckoutCustomerAssociatePayload> + /** Associates a customer to the checkout. */ + checkoutCustomerAssociateV2?: Maybe<CheckoutCustomerAssociateV2Payload> + /** + * Disassociates the current checkout customer from the checkout. + * @deprecated Use `checkoutCustomerDisassociateV2` instead + */ + checkoutCustomerDisassociate?: Maybe<CheckoutCustomerDisassociatePayload> + /** Disassociates the current checkout customer from the checkout. */ + checkoutCustomerDisassociateV2?: Maybe<CheckoutCustomerDisassociateV2Payload> + /** + * Applies a discount to an existing checkout using a discount code. + * @deprecated Use `checkoutDiscountCodeApplyV2` instead + */ + checkoutDiscountCodeApply?: Maybe<CheckoutDiscountCodeApplyPayload> + /** Applies a discount to an existing checkout using a discount code. */ + checkoutDiscountCodeApplyV2?: Maybe<CheckoutDiscountCodeApplyV2Payload> + /** Removes the applied discount from an existing checkout. */ + checkoutDiscountCodeRemove?: Maybe<CheckoutDiscountCodeRemovePayload> + /** + * Updates the email on an existing checkout. + * @deprecated Use `checkoutEmailUpdateV2` instead + */ + checkoutEmailUpdate?: Maybe<CheckoutEmailUpdatePayload> + /** Updates the email on an existing checkout. */ + checkoutEmailUpdateV2?: Maybe<CheckoutEmailUpdateV2Payload> + /** + * Applies a gift card to an existing checkout using a gift card code. This will replace all currently applied gift cards. + * @deprecated Use `checkoutGiftCardsAppend` instead + */ + checkoutGiftCardApply?: Maybe<CheckoutGiftCardApplyPayload> + /** + * Removes an applied gift card from the checkout. + * @deprecated Use `checkoutGiftCardRemoveV2` instead + */ + checkoutGiftCardRemove?: Maybe<CheckoutGiftCardRemovePayload> + /** Removes an applied gift card from the checkout. */ + checkoutGiftCardRemoveV2?: Maybe<CheckoutGiftCardRemoveV2Payload> + /** Appends gift cards to an existing checkout. */ + checkoutGiftCardsAppend?: Maybe<CheckoutGiftCardsAppendPayload> + /** Adds a list of line items to a checkout. */ + checkoutLineItemsAdd?: Maybe<CheckoutLineItemsAddPayload> + /** Removes line items from an existing checkout. */ + checkoutLineItemsRemove?: Maybe<CheckoutLineItemsRemovePayload> + /** Sets a list of line items to a checkout. */ + checkoutLineItemsReplace?: Maybe<CheckoutLineItemsReplacePayload> + /** Updates line items on a checkout. */ + checkoutLineItemsUpdate?: Maybe<CheckoutLineItemsUpdatePayload> + /** + * Updates the shipping address of an existing checkout. + * @deprecated Use `checkoutShippingAddressUpdateV2` instead + */ + checkoutShippingAddressUpdate?: Maybe<CheckoutShippingAddressUpdatePayload> + /** Updates the shipping address of an existing checkout. */ + checkoutShippingAddressUpdateV2?: Maybe<CheckoutShippingAddressUpdateV2Payload> + /** Updates the shipping lines on an existing checkout. */ + checkoutShippingLineUpdate?: Maybe<CheckoutShippingLineUpdatePayload> + /** + * Creates a customer access token. + * The customer access token is required to modify the customer object in any way. + */ + customerAccessTokenCreate?: Maybe<CustomerAccessTokenCreatePayload> + /** + * Creates a customer access token using a multipass token instead of email and password. + * A customer record is created if customer does not exist. If a customer record already + * exists but the record is disabled, then it's enabled. + */ + customerAccessTokenCreateWithMultipass?: Maybe<CustomerAccessTokenCreateWithMultipassPayload> + /** Permanently destroys a customer access token. */ + customerAccessTokenDelete?: Maybe<CustomerAccessTokenDeletePayload> + /** + * Renews a customer access token. + * + * Access token renewal must happen *before* a token expires. + * If a token has already expired, a new one should be created instead via `customerAccessTokenCreate`. + */ + customerAccessTokenRenew?: Maybe<CustomerAccessTokenRenewPayload> + /** Activates a customer. */ + customerActivate?: Maybe<CustomerActivatePayload> + /** Activates a customer with the activation url received from `customerCreate`. */ + customerActivateByUrl?: Maybe<CustomerActivateByUrlPayload> + /** Creates a new address for a customer. */ + customerAddressCreate?: Maybe<CustomerAddressCreatePayload> + /** Permanently deletes the address of an existing customer. */ + customerAddressDelete?: Maybe<CustomerAddressDeletePayload> + /** Updates the address of an existing customer. */ + customerAddressUpdate?: Maybe<CustomerAddressUpdatePayload> + /** Creates a new customer. */ + customerCreate?: Maybe<CustomerCreatePayload> + /** Updates the default address of an existing customer. */ + customerDefaultAddressUpdate?: Maybe<CustomerDefaultAddressUpdatePayload> + /** Sends a reset password email to the customer, as the first step in the reset password process. */ + customerRecover?: Maybe<CustomerRecoverPayload> + /** Resets a customer’s password with a token received from `CustomerRecover`. */ + customerReset?: Maybe<CustomerResetPayload> + /** Resets a customer’s password with the reset password url received from `CustomerRecover`. */ + customerResetByUrl?: Maybe<CustomerResetByUrlPayload> + /** Updates an existing customer. */ + customerUpdate?: Maybe<CustomerUpdatePayload> +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutAttributesUpdateArgs = { + checkoutId: Scalars['ID'] + input: CheckoutAttributesUpdateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutAttributesUpdateV2Args = { + checkoutId: Scalars['ID'] + input: CheckoutAttributesUpdateV2Input +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteFreeArgs = { + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithCreditCardArgs = { + checkoutId: Scalars['ID'] + payment: CreditCardPaymentInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithCreditCardV2Args = { + checkoutId: Scalars['ID'] + payment: CreditCardPaymentInputV2 +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithTokenizedPaymentArgs = { + checkoutId: Scalars['ID'] + payment: TokenizedPaymentInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithTokenizedPaymentV2Args = { + checkoutId: Scalars['ID'] + payment: TokenizedPaymentInputV2 +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithTokenizedPaymentV3Args = { + checkoutId: Scalars['ID'] + payment: TokenizedPaymentInputV3 +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCreateArgs = { + input: CheckoutCreateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCustomerAssociateArgs = { + checkoutId: Scalars['ID'] + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCustomerAssociateV2Args = { + checkoutId: Scalars['ID'] + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCustomerDisassociateArgs = { + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCustomerDisassociateV2Args = { + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutDiscountCodeApplyArgs = { + discountCode: Scalars['String'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutDiscountCodeApplyV2Args = { + discountCode: Scalars['String'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutDiscountCodeRemoveArgs = { + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutEmailUpdateArgs = { + checkoutId: Scalars['ID'] + email: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutEmailUpdateV2Args = { + checkoutId: Scalars['ID'] + email: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutGiftCardApplyArgs = { + giftCardCode: Scalars['String'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutGiftCardRemoveArgs = { + appliedGiftCardId: Scalars['ID'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutGiftCardRemoveV2Args = { + appliedGiftCardId: Scalars['ID'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutGiftCardsAppendArgs = { + giftCardCodes: Array<Scalars['String']> + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutLineItemsAddArgs = { + lineItems: Array<CheckoutLineItemInput> + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutLineItemsRemoveArgs = { + checkoutId: Scalars['ID'] + lineItemIds: Array<Scalars['ID']> +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutLineItemsReplaceArgs = { + lineItems: Array<CheckoutLineItemInput> + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutLineItemsUpdateArgs = { + checkoutId: Scalars['ID'] + lineItems: Array<CheckoutLineItemUpdateInput> +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutShippingAddressUpdateArgs = { + shippingAddress: MailingAddressInput + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutShippingAddressUpdateV2Args = { + shippingAddress: MailingAddressInput + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutShippingLineUpdateArgs = { + checkoutId: Scalars['ID'] + shippingRateHandle: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAccessTokenCreateArgs = { + input: CustomerAccessTokenCreateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAccessTokenCreateWithMultipassArgs = { + multipassToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAccessTokenDeleteArgs = { + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAccessTokenRenewArgs = { + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerActivateArgs = { + id: Scalars['ID'] + input: CustomerActivateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerActivateByUrlArgs = { + activationUrl: Scalars['URL'] + password: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAddressCreateArgs = { + customerAccessToken: Scalars['String'] + address: MailingAddressInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAddressDeleteArgs = { + id: Scalars['ID'] + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAddressUpdateArgs = { + customerAccessToken: Scalars['String'] + id: Scalars['ID'] + address: MailingAddressInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerCreateArgs = { + input: CustomerCreateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerDefaultAddressUpdateArgs = { + customerAccessToken: Scalars['String'] + addressId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerRecoverArgs = { + email: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerResetArgs = { + id: Scalars['ID'] + input: CustomerResetInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerResetByUrlArgs = { + resetUrl: Scalars['URL'] + password: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerUpdateArgs = { + customerAccessToken: Scalars['String'] + customer: CustomerUpdateInput +} + +/** An object with an ID to support global identification. */ +export type Node = { + /** Globally unique identifier. */ + id: Scalars['ID'] +} + +/** An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. */ +export type Order = Node & { + __typename?: 'Order' + /** The reason for the order's cancellation. Returns `null` if the order wasn't canceled. */ + cancelReason?: Maybe<OrderCancelReason> + /** The date and time when the order was canceled. Returns null if the order wasn't canceled. */ + canceledAt?: Maybe<Scalars['DateTime']> + /** The code of the currency used for the payment. */ + currencyCode: CurrencyCode + /** The subtotal of line items and their discounts, excluding line items that have been removed. Does not contain order-level discounts, duties, shipping costs, or shipping discounts. Taxes are not included unless the order is a taxes-included order. */ + currentSubtotalPrice: MoneyV2 + /** The total amount of the order, including duties, taxes and discounts, minus amounts for line items that have been removed. */ + currentTotalPrice: MoneyV2 + /** The total of all taxes applied to the order, excluding taxes for returned line items. */ + currentTotalTax: MoneyV2 + /** The locale code in which this specific order happened. */ + customerLocale?: Maybe<Scalars['String']> + /** The unique URL that the customer can use to access the order. */ + customerUrl?: Maybe<Scalars['URL']> + /** Discounts that have been applied on the order. */ + discountApplications: DiscountApplicationConnection + /** Whether the order has had any edits applied or not. */ + edited: Scalars['Boolean'] + /** The customer's email address. */ + email?: Maybe<Scalars['String']> + /** The financial status of the order. */ + financialStatus?: Maybe<OrderFinancialStatus> + /** The fulfillment status for the order. */ + fulfillmentStatus: OrderFulfillmentStatus + /** Globally unique identifier. */ + id: Scalars['ID'] + /** List of the order’s line items. */ + lineItems: OrderLineItemConnection + /** + * Unique identifier for the order that appears on the order. + * For example, _#1000_ or _Store1001. + */ + name: Scalars['String'] + /** A unique numeric identifier for the order for use by shop owner and customer. */ + orderNumber: Scalars['Int'] + /** The total price of the order before any applied edits. */ + originalTotalPrice: MoneyV2 + /** The customer's phone number for receiving SMS notifications. */ + phone?: Maybe<Scalars['String']> + /** + * The date and time when the order was imported. + * This value can be set to dates in the past when importing from other systems. + * If no value is provided, it will be auto-generated based on current date and time. + */ + processedAt: Scalars['DateTime'] + /** The address to where the order will be shipped. */ + shippingAddress?: Maybe<MailingAddress> + /** The discounts that have been allocated onto the shipping line by discount applications. */ + shippingDiscountAllocations: Array<DiscountAllocation> + /** The unique URL for the order's status page. */ + statusUrl: Scalars['URL'] + /** + * Price of the order before shipping and taxes. + * @deprecated Use `subtotalPriceV2` instead + */ + subtotalPrice?: Maybe<Scalars['Money']> + /** Price of the order before duties, shipping and taxes. */ + subtotalPriceV2?: Maybe<MoneyV2> + /** List of the order’s successful fulfillments. */ + successfulFulfillments?: Maybe<Array<Fulfillment>> + /** + * The sum of all the prices of all the items in the order, taxes and discounts included (must be positive). + * @deprecated Use `totalPriceV2` instead + */ + totalPrice: Scalars['Money'] + /** The sum of all the prices of all the items in the order, duties, taxes and discounts included (must be positive). */ + totalPriceV2: MoneyV2 + /** + * The total amount that has been refunded. + * @deprecated Use `totalRefundedV2` instead + */ + totalRefunded: Scalars['Money'] + /** The total amount that has been refunded. */ + totalRefundedV2: MoneyV2 + /** + * The total cost of shipping. + * @deprecated Use `totalShippingPriceV2` instead + */ + totalShippingPrice: Scalars['Money'] + /** The total cost of shipping. */ + totalShippingPriceV2: MoneyV2 + /** + * The total cost of taxes. + * @deprecated Use `totalTaxV2` instead + */ + totalTax?: Maybe<Scalars['Money']> + /** The total cost of taxes. */ + totalTaxV2?: Maybe<MoneyV2> +} + +/** An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. */ +export type OrderDiscountApplicationsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. */ +export type OrderLineItemsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. */ +export type OrderSuccessfulFulfillmentsArgs = { + first?: Maybe<Scalars['Int']> +} + +/** Represents the reason for the order's cancellation. */ +export enum OrderCancelReason { + /** The customer wanted to cancel the order. */ + Customer = 'CUSTOMER', + /** The order was fraudulent. */ + Fraud = 'FRAUD', + /** There was insufficient inventory. */ + Inventory = 'INVENTORY', + /** Payment was declined. */ + Declined = 'DECLINED', + /** The order was canceled for an unlisted reason. */ + Other = 'OTHER', +} + +/** An auto-generated type for paginating through multiple Orders. */ +export type OrderConnection = { + __typename?: 'OrderConnection' + /** A list of edges. */ + edges: Array<OrderEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Order and a cursor during pagination. */ +export type OrderEdge = { + __typename?: 'OrderEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of OrderEdge. */ + node: Order +} + +/** Represents the order's current financial status. */ +export enum OrderFinancialStatus { + /** Displayed as **Pending**. */ + Pending = 'PENDING', + /** Displayed as **Authorized**. */ + Authorized = 'AUTHORIZED', + /** Displayed as **Partially paid**. */ + PartiallyPaid = 'PARTIALLY_PAID', + /** Displayed as **Partially refunded**. */ + PartiallyRefunded = 'PARTIALLY_REFUNDED', + /** Displayed as **Voided**. */ + Voided = 'VOIDED', + /** Displayed as **Paid**. */ + Paid = 'PAID', + /** Displayed as **Refunded**. */ + Refunded = 'REFUNDED', +} + +/** Represents the order's current fulfillment status. */ +export enum OrderFulfillmentStatus { + /** Displayed as **Unfulfilled**. */ + Unfulfilled = 'UNFULFILLED', + /** Displayed as **Partially fulfilled**. */ + PartiallyFulfilled = 'PARTIALLY_FULFILLED', + /** Displayed as **Fulfilled**. */ + Fulfilled = 'FULFILLED', + /** Displayed as **Restocked**. */ + Restocked = 'RESTOCKED', + /** Displayed as **Pending fulfillment**. */ + PendingFulfillment = 'PENDING_FULFILLMENT', + /** Displayed as **Open**. */ + Open = 'OPEN', + /** Displayed as **In progress**. */ + InProgress = 'IN_PROGRESS', + /** Displayed as **Scheduled**. */ + Scheduled = 'SCHEDULED', +} + +/** Represents a single line in an order. There is one line item for each distinct product variant. */ +export type OrderLineItem = { + __typename?: 'OrderLineItem' + /** The number of entries associated to the line item minus the items that have been removed. */ + currentQuantity: Scalars['Int'] + /** List of custom attributes associated to the line item. */ + customAttributes: Array<Attribute> + /** The discounts that have been allocated onto the order line item by discount applications. */ + discountAllocations: Array<DiscountAllocation> + /** The total price of the line item, including discounts, and displayed in the presentment currency. */ + discountedTotalPrice: MoneyV2 + /** The total price of the line item, not including any discounts. The total price is calculated using the original unit price multiplied by the quantity, and it is displayed in the presentment currency. */ + originalTotalPrice: MoneyV2 + /** The number of products variants associated to the line item. */ + quantity: Scalars['Int'] + /** The title of the product combined with title of the variant. */ + title: Scalars['String'] + /** The product variant object associated to the line item. */ + variant?: Maybe<ProductVariant> +} + +/** An auto-generated type for paginating through multiple OrderLineItems. */ +export type OrderLineItemConnection = { + __typename?: 'OrderLineItemConnection' + /** A list of edges. */ + edges: Array<OrderLineItemEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one OrderLineItem and a cursor during pagination. */ +export type OrderLineItemEdge = { + __typename?: 'OrderLineItemEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of OrderLineItemEdge. */ + node: OrderLineItem +} + +/** The set of valid sort keys for the Order query. */ +export enum OrderSortKeys { + /** Sort by the `processed_at` value. */ + ProcessedAt = 'PROCESSED_AT', + /** Sort by the `total_price` value. */ + TotalPrice = 'TOTAL_PRICE', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** Shopify merchants can create pages to hold static HTML content. Each Page object represents a custom page on the online store. */ +export type Page = Node & { + __typename?: 'Page' + /** The description of the page, complete with HTML formatting. */ + body: Scalars['HTML'] + /** Summary of the page body. */ + bodySummary: Scalars['String'] + /** The timestamp of the page creation. */ + createdAt: Scalars['DateTime'] + /** A human-friendly unique string for the page automatically generated from its title. */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The page's SEO information. */ + seo?: Maybe<Seo> + /** The title of the page. */ + title: Scalars['String'] + /** The timestamp of the latest page update. */ + updatedAt: Scalars['DateTime'] + /** The url pointing to the page accessible from the web. */ + url: Scalars['URL'] +} + +/** An auto-generated type for paginating through multiple Pages. */ +export type PageConnection = { + __typename?: 'PageConnection' + /** A list of edges. */ + edges: Array<PageEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Page and a cursor during pagination. */ +export type PageEdge = { + __typename?: 'PageEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of PageEdge. */ + node: Page +} + +/** Information about pagination in a connection. */ +export type PageInfo = { + __typename?: 'PageInfo' + /** Indicates if there are more pages to fetch. */ + hasNextPage: Scalars['Boolean'] + /** Indicates if there are any pages prior to the current page. */ + hasPreviousPage: Scalars['Boolean'] +} + +/** The set of valid sort keys for the Page query. */ +export enum PageSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `updated_at` value. */ + UpdatedAt = 'UPDATED_AT', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** A payment applied to a checkout. */ +export type Payment = Node & { + __typename?: 'Payment' + /** + * The amount of the payment. + * @deprecated Use `amountV2` instead + */ + amount: Scalars['Money'] + /** The amount of the payment. */ + amountV2: MoneyV2 + /** The billing address for the payment. */ + billingAddress?: Maybe<MailingAddress> + /** The checkout to which the payment belongs. */ + checkout: Checkout + /** The credit card used for the payment in the case of direct payments. */ + creditCard?: Maybe<CreditCard> + /** A message describing a processing error during asynchronous processing. */ + errorMessage?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** A client-side generated token to identify a payment and perform idempotent operations. */ + idempotencyKey?: Maybe<Scalars['String']> + /** The URL where the customer needs to be redirected so they can complete the 3D Secure payment flow. */ + nextActionUrl?: Maybe<Scalars['URL']> + /** Whether or not the payment is still processing asynchronously. */ + ready: Scalars['Boolean'] + /** A flag to indicate if the payment is to be done in test mode for gateways that support it. */ + test: Scalars['Boolean'] + /** The actual transaction recorded by Shopify after having processed the payment with the gateway. */ + transaction?: Maybe<Transaction> +} + +/** Settings related to payments. */ +export type PaymentSettings = { + __typename?: 'PaymentSettings' + /** List of the card brands which the shop accepts. */ + acceptedCardBrands: Array<CardBrand> + /** The url pointing to the endpoint to vault credit cards. */ + cardVaultUrl: Scalars['URL'] + /** The country where the shop is located. */ + countryCode: CountryCode + /** The three-letter code for the shop's primary currency. */ + currencyCode: CurrencyCode + /** A list of enabled currencies (ISO 4217 format) that the shop accepts. Merchants can enable currencies from their Shopify Payments settings in the Shopify admin. */ + enabledPresentmentCurrencies: Array<CurrencyCode> + /** The shop’s Shopify Payments account id. */ + shopifyPaymentsAccountId?: Maybe<Scalars['String']> + /** List of the digital wallets which the shop supports. */ + supportedDigitalWallets: Array<DigitalWallet> +} + +/** The valid values for the types of payment token. */ +export enum PaymentTokenType { + /** Apple Pay token type. */ + ApplePay = 'APPLE_PAY', + /** Vault payment token type. */ + Vault = 'VAULT', + /** Shopify Pay token type. */ + ShopifyPay = 'SHOPIFY_PAY', + /** Google Pay token type. */ + GooglePay = 'GOOGLE_PAY', +} + +/** The value of the percentage pricing object. */ +export type PricingPercentageValue = { + __typename?: 'PricingPercentageValue' + /** The percentage value of the object. */ + percentage: Scalars['Float'] +} + +/** The price value (fixed or percentage) for a discount application. */ +export type PricingValue = MoneyV2 | PricingPercentageValue + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type Product = Node & + HasMetafields & { + __typename?: 'Product' + /** Indicates if at least one product variant is available for sale. */ + availableForSale: Scalars['Boolean'] + /** List of collections a product belongs to. */ + collections: CollectionConnection + /** The compare at price of the product across all variants. */ + compareAtPriceRange: ProductPriceRange + /** The date and time when the product was created. */ + createdAt: Scalars['DateTime'] + /** Stripped description of the product, single line with HTML tags removed. */ + description: Scalars['String'] + /** The description of the product, complete with HTML formatting. */ + descriptionHtml: Scalars['HTML'] + /** + * A human-friendly unique string for the Product automatically generated from its title. + * They are used by the Liquid templating language to refer to objects. + */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** List of images associated with the product. */ + images: ImageConnection + /** The media associated with the product. */ + media: MediaConnection + /** The metafield associated with the resource. */ + metafield?: Maybe<Metafield> + /** A paginated list of metafields associated with the resource. */ + metafields: MetafieldConnection + /** + * The online store URL for the product. + * A value of `null` indicates that the product is not published to the Online Store sales channel. + */ + onlineStoreUrl?: Maybe<Scalars['URL']> + /** List of product options. */ + options: Array<ProductOption> + /** List of price ranges in the presentment currencies for this shop. */ + presentmentPriceRanges: ProductPriceRangeConnection + /** The price range. */ + priceRange: ProductPriceRange + /** A categorization that a product can be tagged with, commonly used for filtering and searching. */ + productType: Scalars['String'] + /** The date and time when the product was published to the channel. */ + publishedAt: Scalars['DateTime'] + /** The product's SEO information. */ + seo: Seo + /** + * A comma separated list of tags that have been added to the product. + * Additional access scope required for private apps: unauthenticated_read_product_tags. + */ + tags: Array<Scalars['String']> + /** The product’s title. */ + title: Scalars['String'] + /** The total quantity of inventory in stock for this Product. */ + totalInventory?: Maybe<Scalars['Int']> + /** + * The date and time when the product was last modified. + * A product's `updatedAt` value can change for different reasons. For example, if an order + * is placed for a product that has inventory tracking set up, then the inventory adjustment + * is counted as an update. + */ + updatedAt: Scalars['DateTime'] + /** + * Find a product’s variant based on its selected options. + * This is useful for converting a user’s selection of product options into a single matching variant. + * If there is not a variant for the selected options, `null` will be returned. + */ + variantBySelectedOptions?: Maybe<ProductVariant> + /** List of the product’s variants. */ + variants: ProductVariantConnection + /** The product’s vendor name. */ + vendor: Scalars['String'] + } + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductCollectionsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductDescriptionArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductImagesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductImageSortKeys> + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductMediaArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductMediaSortKeys> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductMetafieldArgs = { + namespace: Scalars['String'] + key: Scalars['String'] +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductMetafieldsArgs = { + namespace?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductOptionsArgs = { + first?: Maybe<Scalars['Int']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductPresentmentPriceRangesArgs = { + presentmentCurrencies?: Maybe<Array<CurrencyCode>> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductVariantBySelectedOptionsArgs = { + selectedOptions: Array<SelectedOptionInput> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductVariantsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductVariantSortKeys> +} + +/** The set of valid sort keys for the ProductCollection query. */ +export enum ProductCollectionSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `price` value. */ + Price = 'PRICE', + /** Sort by the `best-selling` value. */ + BestSelling = 'BEST_SELLING', + /** Sort by the `created` value. */ + Created = 'CREATED', + /** Sort by the `id` value. */ + Id = 'ID', + /** Sort by the `manual` value. */ + Manual = 'MANUAL', + /** Sort by the `collection-default` value. */ + CollectionDefault = 'COLLECTION_DEFAULT', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** An auto-generated type for paginating through multiple Products. */ +export type ProductConnection = { + __typename?: 'ProductConnection' + /** A list of edges. */ + edges: Array<ProductEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Product and a cursor during pagination. */ +export type ProductEdge = { + __typename?: 'ProductEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ProductEdge. */ + node: Product +} + +/** The set of valid sort keys for the ProductImage query. */ +export enum ProductImageSortKeys { + /** Sort by the `created_at` value. */ + CreatedAt = 'CREATED_AT', + /** Sort by the `position` value. */ + Position = 'POSITION', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** The set of valid sort keys for the ProductMedia query. */ +export enum ProductMediaSortKeys { + /** Sort by the `position` value. */ + Position = 'POSITION', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** + * Product property names like "Size", "Color", and "Material" that the customers can select. + * Variants are selected based on permutations of these options. + * 255 characters limit each. + */ +export type ProductOption = Node & { + __typename?: 'ProductOption' + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The product option’s name. */ + name: Scalars['String'] + /** The corresponding value to the product option name. */ + values: Array<Scalars['String']> +} + +/** The price range of the product. */ +export type ProductPriceRange = { + __typename?: 'ProductPriceRange' + /** The highest variant's price. */ + maxVariantPrice: MoneyV2 + /** The lowest variant's price. */ + minVariantPrice: MoneyV2 +} + +/** An auto-generated type for paginating through multiple ProductPriceRanges. */ +export type ProductPriceRangeConnection = { + __typename?: 'ProductPriceRangeConnection' + /** A list of edges. */ + edges: Array<ProductPriceRangeEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one ProductPriceRange and a cursor during pagination. */ +export type ProductPriceRangeEdge = { + __typename?: 'ProductPriceRangeEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ProductPriceRangeEdge. */ + node: ProductPriceRange +} + +/** The set of valid sort keys for the Product query. */ +export enum ProductSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `product_type` value. */ + ProductType = 'PRODUCT_TYPE', + /** Sort by the `vendor` value. */ + Vendor = 'VENDOR', + /** Sort by the `updated_at` value. */ + UpdatedAt = 'UPDATED_AT', + /** Sort by the `created_at` value. */ + CreatedAt = 'CREATED_AT', + /** Sort by the `best_selling` value. */ + BestSelling = 'BEST_SELLING', + /** Sort by the `price` value. */ + Price = 'PRICE', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariant = Node & + HasMetafields & { + __typename?: 'ProductVariant' + /** + * Indicates if the product variant is in stock. + * @deprecated Use `availableForSale` instead + */ + available?: Maybe<Scalars['Boolean']> + /** Indicates if the product variant is available for sale. */ + availableForSale: Scalars['Boolean'] + /** + * The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPrice` is higher than `price`. + * @deprecated Use `compareAtPriceV2` instead + */ + compareAtPrice?: Maybe<Scalars['Money']> + /** The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPriceV2` is higher than `priceV2`. */ + compareAtPriceV2?: Maybe<MoneyV2> + /** Whether a product is out of stock but still available for purchase (used for backorders). */ + currentlyNotInStock: Scalars['Boolean'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** Image associated with the product variant. This field falls back to the product image if no image is available. */ + image?: Maybe<Image> + /** The metafield associated with the resource. */ + metafield?: Maybe<Metafield> + /** A paginated list of metafields associated with the resource. */ + metafields: MetafieldConnection + /** List of prices and compare-at prices in the presentment currencies for this shop. */ + presentmentPrices: ProductVariantPricePairConnection + /** List of unit prices in the presentment currencies for this shop. */ + presentmentUnitPrices: MoneyV2Connection + /** + * The product variant’s price. + * @deprecated Use `priceV2` instead + */ + price: Scalars['Money'] + /** The product variant’s price. */ + priceV2: MoneyV2 + /** The product object that the product variant belongs to. */ + product: Product + /** The total sellable quantity of the variant for online sales channels. */ + quantityAvailable?: Maybe<Scalars['Int']> + /** Whether a customer needs to provide a shipping address when placing an order for the product variant. */ + requiresShipping: Scalars['Boolean'] + /** List of product options applied to the variant. */ + selectedOptions: Array<SelectedOption> + /** The SKU (stock keeping unit) associated with the variant. */ + sku?: Maybe<Scalars['String']> + /** The product variant’s title. */ + title: Scalars['String'] + /** The unit price value for the variant based on the variant's measurement. */ + unitPrice?: Maybe<MoneyV2> + /** The unit price measurement for the variant. */ + unitPriceMeasurement?: Maybe<UnitPriceMeasurement> + /** The weight of the product variant in the unit system specified with `weight_unit`. */ + weight?: Maybe<Scalars['Float']> + /** Unit of measurement for weight. */ + weightUnit: WeightUnit + } + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantImageArgs = { + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantMetafieldArgs = { + namespace: Scalars['String'] + key: Scalars['String'] +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantMetafieldsArgs = { + namespace?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantPresentmentPricesArgs = { + presentmentCurrencies?: Maybe<Array<CurrencyCode>> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantPresentmentUnitPricesArgs = { + presentmentCurrencies?: Maybe<Array<CurrencyCode>> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** An auto-generated type for paginating through multiple ProductVariants. */ +export type ProductVariantConnection = { + __typename?: 'ProductVariantConnection' + /** A list of edges. */ + edges: Array<ProductVariantEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one ProductVariant and a cursor during pagination. */ +export type ProductVariantEdge = { + __typename?: 'ProductVariantEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ProductVariantEdge. */ + node: ProductVariant +} + +/** The compare-at price and price of a variant sharing a currency. */ +export type ProductVariantPricePair = { + __typename?: 'ProductVariantPricePair' + /** The compare-at price of the variant with associated currency. */ + compareAtPrice?: Maybe<MoneyV2> + /** The price of the variant with associated currency. */ + price: MoneyV2 +} + +/** An auto-generated type for paginating through multiple ProductVariantPricePairs. */ +export type ProductVariantPricePairConnection = { + __typename?: 'ProductVariantPricePairConnection' + /** A list of edges. */ + edges: Array<ProductVariantPricePairEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one ProductVariantPricePair and a cursor during pagination. */ +export type ProductVariantPricePairEdge = { + __typename?: 'ProductVariantPricePairEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ProductVariantPricePairEdge. */ + node: ProductVariantPricePair +} + +/** The set of valid sort keys for the ProductVariant query. */ +export enum ProductVariantSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `sku` value. */ + Sku = 'SKU', + /** Sort by the `position` value. */ + Position = 'POSITION', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRoot = { + __typename?: 'QueryRoot' + /** List of the shop's articles. */ + articles: ArticleConnection + /** Find a blog by its handle. */ + blogByHandle?: Maybe<Blog> + /** List of the shop's blogs. */ + blogs: BlogConnection + /** Find a collection by its handle. */ + collectionByHandle?: Maybe<Collection> + /** List of the shop’s collections. */ + collections: CollectionConnection + /** Find a customer by its access token. */ + customer?: Maybe<Customer> + node?: Maybe<Node> + nodes: Array<Maybe<Node>> + /** Find a page by its handle. */ + pageByHandle?: Maybe<Page> + /** List of the shop's pages. */ + pages: PageConnection + /** Find a product by its handle. */ + productByHandle?: Maybe<Product> + /** + * Find recommended products related to a given `product_id`. + * To learn more about how recommendations are generated, see + * [*Showing product recommendations on product pages*](https://help.shopify.com/themes/development/recommended-products). + */ + productRecommendations?: Maybe<Array<Product>> + /** + * Tags added to products. + * Additional access scope required: unauthenticated_read_product_tags. + */ + productTags: StringConnection + /** List of product types for the shop's products that are published to your app. */ + productTypes: StringConnection + /** List of the shop’s products. */ + products: ProductConnection + /** The list of public Storefront API versions, including supported, release candidate and unstable versions. */ + publicApiVersions: Array<ApiVersion> + /** The shop associated with the storefront access token. */ + shop: Shop +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootArticlesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ArticleSortKeys> + query?: Maybe<Scalars['String']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootBlogByHandleArgs = { + handle: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootBlogsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<BlogSortKeys> + query?: Maybe<Scalars['String']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootCollectionByHandleArgs = { + handle: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootCollectionsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<CollectionSortKeys> + query?: Maybe<Scalars['String']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootCustomerArgs = { + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootNodeArgs = { + id: Scalars['ID'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootNodesArgs = { + ids: Array<Scalars['ID']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootPageByHandleArgs = { + handle: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootPagesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<PageSortKeys> + query?: Maybe<Scalars['String']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductByHandleArgs = { + handle: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductRecommendationsArgs = { + productId: Scalars['ID'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductTagsArgs = { + first: Scalars['Int'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductTypesArgs = { + first: Scalars['Int'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductSortKeys> + query?: Maybe<Scalars['String']> +} + +/** SEO information. */ +export type Seo = { + __typename?: 'SEO' + /** The meta description. */ + description?: Maybe<Scalars['String']> + /** The SEO title. */ + title?: Maybe<Scalars['String']> +} + +/** + * Script discount applications capture the intentions of a discount that + * was created by a Shopify Script. + */ +export type ScriptDiscountApplication = DiscountApplication & { + __typename?: 'ScriptDiscountApplication' + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** + * The description of the application as defined by the Script. + * @deprecated Use `title` instead + */ + description: Scalars['String'] + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The title of the application as defined by the Script. */ + title: Scalars['String'] + /** The value of the discount application. */ + value: PricingValue +} + +/** + * Properties used by customers to select a product variant. + * Products can have multiple options, like different sizes or colors. + */ +export type SelectedOption = { + __typename?: 'SelectedOption' + /** The product option’s name. */ + name: Scalars['String'] + /** The product option’s value. */ + value: Scalars['String'] +} + +/** Specifies the input fields required for a selected option. */ +export type SelectedOptionInput = { + /** The product option’s name. */ + name: Scalars['String'] + /** The product option’s value. */ + value: Scalars['String'] +} + +/** A shipping rate to be applied to a checkout. */ +export type ShippingRate = { + __typename?: 'ShippingRate' + /** Human-readable unique identifier for this shipping rate. */ + handle: Scalars['String'] + /** + * Price of this shipping rate. + * @deprecated Use `priceV2` instead + */ + price: Scalars['Money'] + /** Price of this shipping rate. */ + priceV2: MoneyV2 + /** Title of this shipping rate. */ + title: Scalars['String'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type Shop = { + __typename?: 'Shop' + /** + * List of the shop' articles. + * @deprecated Use `QueryRoot.articles` instead. + */ + articles: ArticleConnection + /** + * List of the shop' blogs. + * @deprecated Use `QueryRoot.blogs` instead. + */ + blogs: BlogConnection + /** + * Find a collection by its handle. + * @deprecated Use `QueryRoot.collectionByHandle` instead. + */ + collectionByHandle?: Maybe<Collection> + /** + * List of the shop’s collections. + * @deprecated Use `QueryRoot.collections` instead. + */ + collections: CollectionConnection + /** + * The three-letter code for the currency that the shop accepts. + * @deprecated Use `paymentSettings` instead + */ + currencyCode: CurrencyCode + /** A description of the shop. */ + description?: Maybe<Scalars['String']> + /** A string representing the way currency is formatted when the currency isn’t specified. */ + moneyFormat: Scalars['String'] + /** The shop’s name. */ + name: Scalars['String'] + /** Settings related to payments. */ + paymentSettings: PaymentSettings + /** The shop’s primary domain. */ + primaryDomain: Domain + /** The shop’s privacy policy. */ + privacyPolicy?: Maybe<ShopPolicy> + /** + * Find a product by its handle. + * @deprecated Use `QueryRoot.productByHandle` instead. + */ + productByHandle?: Maybe<Product> + /** + * A list of tags that have been added to products. + * Additional access scope required: unauthenticated_read_product_tags. + * @deprecated Use `QueryRoot.productTags` instead. + */ + productTags: StringConnection + /** + * List of the shop’s product types. + * @deprecated Use `QueryRoot.productTypes` instead. + */ + productTypes: StringConnection + /** + * List of the shop’s products. + * @deprecated Use `QueryRoot.products` instead. + */ + products: ProductConnection + /** The shop’s refund policy. */ + refundPolicy?: Maybe<ShopPolicy> + /** The shop’s shipping policy. */ + shippingPolicy?: Maybe<ShopPolicy> + /** Countries that the shop ships to. */ + shipsToCountries: Array<CountryCode> + /** + * The shop’s Shopify Payments account id. + * @deprecated Use `paymentSettings` instead + */ + shopifyPaymentsAccountId?: Maybe<Scalars['String']> + /** The shop’s terms of service. */ + termsOfService?: Maybe<ShopPolicy> +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopArticlesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ArticleSortKeys> + query?: Maybe<Scalars['String']> +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopBlogsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<BlogSortKeys> + query?: Maybe<Scalars['String']> +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopCollectionByHandleArgs = { + handle: Scalars['String'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopCollectionsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<CollectionSortKeys> + query?: Maybe<Scalars['String']> +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopProductByHandleArgs = { + handle: Scalars['String'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopProductTagsArgs = { + first: Scalars['Int'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopProductTypesArgs = { + first: Scalars['Int'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopProductsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductSortKeys> + query?: Maybe<Scalars['String']> +} + +/** Policy that a merchant has configured for their store, such as their refund or privacy policy. */ +export type ShopPolicy = Node & { + __typename?: 'ShopPolicy' + /** Policy text, maximum size of 64kb. */ + body: Scalars['String'] + /** Policy’s handle. */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** Policy’s title. */ + title: Scalars['String'] + /** Public URL to the policy. */ + url: Scalars['URL'] +} + +/** An auto-generated type for paginating through multiple Strings. */ +export type StringConnection = { + __typename?: 'StringConnection' + /** A list of edges. */ + edges: Array<StringEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one String and a cursor during pagination. */ +export type StringEdge = { + __typename?: 'StringEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of StringEdge. */ + node: Scalars['String'] +} + +/** + * Specifies the fields required to complete a checkout with + * a tokenized payment. + */ +export type TokenizedPaymentInput = { + /** The amount of the payment. */ + amount: Scalars['Money'] + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** The type of payment token. */ + type: Scalars['String'] + /** A simple string or JSON containing the required payment data for the tokenized payment. */ + paymentData: Scalars['String'] + /** Executes the payment in test mode if possible. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> + /** Public Hash Key used for AndroidPay payments only. */ + identifier?: Maybe<Scalars['String']> +} + +/** + * Specifies the fields required to complete a checkout with + * a tokenized payment. + */ +export type TokenizedPaymentInputV2 = { + /** The amount and currency of the payment. */ + paymentAmount: MoneyInput + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** A simple string or JSON containing the required payment data for the tokenized payment. */ + paymentData: Scalars['String'] + /** Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> + /** Public Hash Key used for AndroidPay payments only. */ + identifier?: Maybe<Scalars['String']> + /** The type of payment token. */ + type: Scalars['String'] +} + +/** + * Specifies the fields required to complete a checkout with + * a tokenized payment. + */ +export type TokenizedPaymentInputV3 = { + /** The amount and currency of the payment. */ + paymentAmount: MoneyInput + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** A simple string or JSON containing the required payment data for the tokenized payment. */ + paymentData: Scalars['String'] + /** Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> + /** Public Hash Key used for AndroidPay payments only. */ + identifier?: Maybe<Scalars['String']> + /** The type of payment token. */ + type: PaymentTokenType +} + +/** An object representing exchange of money for a product or service. */ +export type Transaction = { + __typename?: 'Transaction' + /** + * The amount of money that the transaction was for. + * @deprecated Use `amountV2` instead + */ + amount: Scalars['Money'] + /** The amount of money that the transaction was for. */ + amountV2: MoneyV2 + /** The kind of the transaction. */ + kind: TransactionKind + /** + * The status of the transaction. + * @deprecated Use `statusV2` instead + */ + status: TransactionStatus + /** The status of the transaction. */ + statusV2?: Maybe<TransactionStatus> + /** Whether the transaction was done in test mode or not. */ + test: Scalars['Boolean'] +} + +export enum TransactionKind { + Sale = 'SALE', + Capture = 'CAPTURE', + Authorization = 'AUTHORIZATION', + EmvAuthorization = 'EMV_AUTHORIZATION', + Change = 'CHANGE', +} + +export enum TransactionStatus { + Pending = 'PENDING', + Success = 'SUCCESS', + Failure = 'FAILURE', + Error = 'ERROR', +} + +/** The measurement used to calculate a unit price for a product variant (e.g. $9.99 / 100ml). */ +export type UnitPriceMeasurement = { + __typename?: 'UnitPriceMeasurement' + /** The type of unit of measurement for the unit price measurement. */ + measuredType?: Maybe<UnitPriceMeasurementMeasuredType> + /** The quantity unit for the unit price measurement. */ + quantityUnit?: Maybe<UnitPriceMeasurementMeasuredUnit> + /** The quantity value for the unit price measurement. */ + quantityValue: Scalars['Float'] + /** The reference unit for the unit price measurement. */ + referenceUnit?: Maybe<UnitPriceMeasurementMeasuredUnit> + /** The reference value for the unit price measurement. */ + referenceValue: Scalars['Int'] +} + +/** The accepted types of unit of measurement. */ +export enum UnitPriceMeasurementMeasuredType { + /** Unit of measurements representing volumes. */ + Volume = 'VOLUME', + /** Unit of measurements representing weights. */ + Weight = 'WEIGHT', + /** Unit of measurements representing lengths. */ + Length = 'LENGTH', + /** Unit of measurements representing areas. */ + Area = 'AREA', +} + +/** The valid units of measurement for a unit price measurement. */ +export enum UnitPriceMeasurementMeasuredUnit { + /** 1000 milliliters equals 1 liter. */ + Ml = 'ML', + /** 100 centiliters equals 1 liter. */ + Cl = 'CL', + /** Metric system unit of volume. */ + L = 'L', + /** 1 cubic meter equals 1000 liters. */ + M3 = 'M3', + /** 1000 milligrams equals 1 gram. */ + Mg = 'MG', + /** Metric system unit of weight. */ + G = 'G', + /** 1 kilogram equals 1000 grams. */ + Kg = 'KG', + /** 1000 millimeters equals 1 meter. */ + Mm = 'MM', + /** 100 centimeters equals 1 meter. */ + Cm = 'CM', + /** Metric system unit of length. */ + M = 'M', + /** Metric system unit of area. */ + M2 = 'M2', +} + +/** Represents an error in the input of a mutation. */ +export type UserError = DisplayableError & { + __typename?: 'UserError' + /** Path to the input field which caused the error. */ + field?: Maybe<Array<Scalars['String']>> + /** The error message. */ + message: Scalars['String'] +} + +/** Represents a Shopify hosted video. */ +export type Video = Node & + Media & { + __typename?: 'Video' + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> + /** The sources for a video. */ + sources: Array<VideoSource> + } + +/** Represents a source for a Shopify hosted video. */ +export type VideoSource = { + __typename?: 'VideoSource' + /** The format of the video source. */ + format: Scalars['String'] + /** The height of the video. */ + height: Scalars['Int'] + /** The video MIME type. */ + mimeType: Scalars['String'] + /** The URL of the video. */ + url: Scalars['String'] + /** The width of the video. */ + width: Scalars['Int'] +} + +/** Units of measurement for weight. */ +export enum WeightUnit { + /** 1 kilogram equals 1000 grams. */ + Kilograms = 'KILOGRAMS', + /** Metric system unit of mass. */ + Grams = 'GRAMS', + /** 1 pound equals 16 ounces. */ + Pounds = 'POUNDS', + /** Imperial system unit of mass. */ + Ounces = 'OUNCES', +} + +export type Unnamed_1_QueryVariables = Exact<{ + first: Scalars['Int'] +}> + +export type Unnamed_1_Query = { __typename?: 'QueryRoot' } & { + pages: { __typename?: 'PageConnection' } & { + edges: Array< + { __typename?: 'PageEdge' } & { + node: { __typename?: 'Page' } & Pick< + Page, + 'id' | 'title' | 'handle' | 'body' | 'bodySummary' | 'url' + > + } + > + } +} diff --git a/framework/shopify/schema.graphql b/framework/shopify/schema.graphql new file mode 100644 index 00000000..822e6007 --- /dev/null +++ b/framework/shopify/schema.graphql @@ -0,0 +1,9631 @@ +schema { + query: QueryRoot + mutation: Mutation +} + +""" +Marks an element of a GraphQL schema as having restricted access. +""" +directive @accessRestricted( + """ + Explains the reason around this restriction + """ + reason: String = null +) on FIELD_DEFINITION | OBJECT + +""" +A version of the API. +""" +type ApiVersion { + """ + The human-readable name of the version. + """ + displayName: String! + + """ + The unique identifier of an ApiVersion. All supported API versions have a date-based (YYYY-MM) or `unstable` handle. + """ + handle: String! + + """ + Whether the version is supported by Shopify. + """ + supported: Boolean! +} + +""" +Details about the gift card used on the checkout. +""" +type AppliedGiftCard implements Node { + """ + The amount that was taken from the gift card by applying it. + """ + amountUsed: Money! @deprecated(reason: "Use `amountUsedV2` instead") + + """ + The amount that was taken from the gift card by applying it. + """ + amountUsedV2: MoneyV2! + + """ + The amount left on the gift card. + """ + balance: Money! @deprecated(reason: "Use `balanceV2` instead") + + """ + The amount left on the gift card. + """ + balanceV2: MoneyV2! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The last characters of the gift card. + """ + lastCharacters: String! + + """ + The amount that was applied to the checkout in its currency. + """ + presentmentAmountUsed: MoneyV2! +} + +""" +An article in an online store blog. +""" +type Article implements Node { + """ + The article's author. + """ + author: ArticleAuthor! @deprecated(reason: "Use `authorV2` instead") + + """ + The article's author. + """ + authorV2: ArticleAuthor + + """ + The blog that the article belongs to. + """ + blog: Blog! + + """ + List of comments posted on the article. + """ + comments( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): CommentConnection! + + """ + Stripped content of the article, single line with HTML tags removed. + """ + content( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String! + + """ + The content of the article, complete with HTML formatting. + """ + contentHtml: HTML! + + """ + Stripped excerpt of the article, single line with HTML tags removed. + """ + excerpt( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String + + """ + The excerpt of the article, complete with HTML formatting. + """ + excerptHtml: HTML + + """ + A human-friendly unique string for the Article automatically generated from its title. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The image associated with the article. + """ + image( + """ + Image width in pixels between 1 and 2048. This argument is deprecated: Use `maxWidth` on `Image.transformedSrc` instead. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 2048. This argument is deprecated: Use `maxHeight` on `Image.transformedSrc` instead. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. This argument is deprecated: Use `crop` on `Image.transformedSrc` instead. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. This argument is deprecated: Use `scale` on `Image.transformedSrc` instead. + """ + scale: Int = 1 + ): Image + + """ + The date and time when the article was published. + """ + publishedAt: DateTime! + + """ + The article’s SEO information. + """ + seo: SEO + + """ + A categorization that a article can be tagged with. + """ + tags: [String!]! + + """ + The article’s name. + """ + title: String! + + """ + The url pointing to the article accessible from the web. + """ + url: URL! +} + +""" +The author of an article. +""" +type ArticleAuthor { + """ + The author's bio. + """ + bio: String + + """ + The author’s email. + """ + email: String! + + """ + The author's first name. + """ + firstName: String! + + """ + The author's last name. + """ + lastName: String! + + """ + The author's full name. + """ + name: String! +} + +""" +An auto-generated type for paginating through multiple Articles. +""" +type ArticleConnection { + """ + A list of edges. + """ + edges: [ArticleEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Article and a cursor during pagination. +""" +type ArticleEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ArticleEdge. + """ + node: Article! +} + +""" +The set of valid sort keys for the Article query. +""" +enum ArticleSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `blog_title` value. + """ + BLOG_TITLE + + """ + Sort by the `author` value. + """ + AUTHOR + + """ + Sort by the `updated_at` value. + """ + UPDATED_AT + + """ + Sort by the `published_at` value. + """ + PUBLISHED_AT + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +Represents a generic custom attribute. +""" +type Attribute { + """ + Key or name of the attribute. + """ + key: String! + + """ + Value of the attribute. + """ + value: String +} + +""" +Specifies the input fields required for an attribute. +""" +input AttributeInput { + """ + Key or name of the attribute. + """ + key: String! + + """ + Value of the attribute. + """ + value: String! +} + +""" +Automatic discount applications capture the intentions of a discount that was automatically applied. +""" +type AutomaticDiscountApplication implements DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The title of the application. + """ + title: String! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +A collection of available shipping rates for a checkout. +""" +type AvailableShippingRates { + """ + Whether or not the shipping rates are ready. + The `shippingRates` field is `null` when this value is `false`. + This field should be polled until its value becomes `true`. + """ + ready: Boolean! + + """ + The fetched shipping rates. `null` until the `ready` field is `true`. + """ + shippingRates: [ShippingRate!] +} + +""" +An online store blog. +""" +type Blog implements Node { + """ + Find an article by its handle. + """ + articleByHandle( + """ + The handle of the article. + """ + handle: String! + ): Article + + """ + List of the blog's articles. + """ + articles( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ArticleSortKeys = ID + + """ + Supported filter parameters: + - `author` + - `blog_title` + - `created_at` + - `tag` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ArticleConnection! + + """ + The authors who have contributed to the blog. + """ + authors: [ArticleAuthor!]! + + """ + A human-friendly unique string for the Blog automatically generated from its title. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The blog's SEO information. + """ + seo: SEO + + """ + The blogs’s title. + """ + title: String! + + """ + The url pointing to the blog accessible from the web. + """ + url: URL! +} + +""" +An auto-generated type for paginating through multiple Blogs. +""" +type BlogConnection { + """ + A list of edges. + """ + edges: [BlogEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Blog and a cursor during pagination. +""" +type BlogEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of BlogEdge. + """ + node: Blog! +} + +""" +The set of valid sort keys for the Blog query. +""" +enum BlogSortKeys { + """ + Sort by the `handle` value. + """ + HANDLE + + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +Card brand, such as Visa or Mastercard, which can be used for payments. +""" +enum CardBrand { + """ + Visa + """ + VISA + + """ + Mastercard + """ + MASTERCARD + + """ + Discover + """ + DISCOVER + + """ + American Express + """ + AMERICAN_EXPRESS + + """ + Diners Club + """ + DINERS_CLUB + + """ + JCB + """ + JCB +} + +""" +A container for all the information required to checkout items and pay. +""" +type Checkout implements Node { + """ + The gift cards used on the checkout. + """ + appliedGiftCards: [AppliedGiftCard!]! + + """ + The available shipping rates for this Checkout. + Should only be used when checkout `requiresShipping` is `true` and + the shipping address is valid. + """ + availableShippingRates: AvailableShippingRates + + """ + The date and time when the checkout was completed. + """ + completedAt: DateTime + + """ + The date and time when the checkout was created. + """ + createdAt: DateTime! + + """ + The currency code for the Checkout. + """ + currencyCode: CurrencyCode! + + """ + A list of extra information that is added to the checkout. + """ + customAttributes: [Attribute!]! + + """ + The customer associated with the checkout. + """ + customer: Customer + @deprecated( + reason: "This field will always return null. If you have an authentication token for the customer, you can use the `customer` field on the query root to retrieve it." + ) + + """ + Discounts that have been applied on the checkout. + """ + discountApplications( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): DiscountApplicationConnection! + + """ + The email attached to this checkout. + """ + email: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + A list of line item objects, each one containing information about an item in the checkout. + """ + lineItems( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): CheckoutLineItemConnection! + + """ + The sum of all the prices of all the items in the checkout. Duties, taxes, shipping and discounts excluded. + """ + lineItemsSubtotalPrice: MoneyV2! + + """ + The note associated with the checkout. + """ + note: String + + """ + The resulting order from a paid checkout. + """ + order: Order + + """ + The Order Status Page for this Checkout, null when checkout is not completed. + """ + orderStatusUrl: URL + + """ + The amount left to be paid. This is equal to the cost of the line items, taxes and shipping minus discounts and gift cards. + """ + paymentDue: Money! @deprecated(reason: "Use `paymentDueV2` instead") + + """ + The amount left to be paid. This is equal to the cost of the line items, duties, taxes and shipping minus discounts and gift cards. + """ + paymentDueV2: MoneyV2! + + """ + Whether or not the Checkout is ready and can be completed. Checkouts may + have asynchronous operations that can take time to finish. If you want + to complete a checkout or ensure all the fields are populated and up to + date, polling is required until the value is true. + """ + ready: Boolean! + + """ + States whether or not the fulfillment requires shipping. + """ + requiresShipping: Boolean! + + """ + The shipping address to where the line items will be shipped. + """ + shippingAddress: MailingAddress + + """ + The discounts that have been allocated onto the shipping line by discount applications. + """ + shippingDiscountAllocations: [DiscountAllocation!]! + + """ + Once a shipping rate is selected by the customer it is transitioned to a `shipping_line` object. + """ + shippingLine: ShippingRate + + """ + Price of the checkout before shipping and taxes. + """ + subtotalPrice: Money! @deprecated(reason: "Use `subtotalPriceV2` instead") + + """ + Price of the checkout before duties, shipping and taxes. + """ + subtotalPriceV2: MoneyV2! + + """ + Specifies if the Checkout is tax exempt. + """ + taxExempt: Boolean! + + """ + Specifies if taxes are included in the line item and shipping line prices. + """ + taxesIncluded: Boolean! + + """ + The sum of all the prices of all the items in the checkout, taxes and discounts included. + """ + totalPrice: Money! @deprecated(reason: "Use `totalPriceV2` instead") + + """ + The sum of all the prices of all the items in the checkout, duties, taxes and discounts included. + """ + totalPriceV2: MoneyV2! + + """ + The sum of all the taxes applied to the line items and shipping lines in the checkout. + """ + totalTax: Money! @deprecated(reason: "Use `totalTaxV2` instead") + + """ + The sum of all the taxes applied to the line items and shipping lines in the checkout. + """ + totalTaxV2: MoneyV2! + + """ + The date and time when the checkout was last updated. + """ + updatedAt: DateTime! + + """ + The url pointing to the checkout accessible from the web. + """ + webUrl: URL! +} + +""" +Specifies the fields required to update a checkout's attributes. +""" +input CheckoutAttributesUpdateInput { + """ + The text of an optional note that a shop owner can attach to the checkout. + """ + note: String + + """ + A list of extra information that is added to the checkout. + """ + customAttributes: [AttributeInput!] + + """ + Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + The required attributes are city, province, and country. + Full validation of the addresses is still done at complete time. + """ + allowPartialAddresses: Boolean +} + +""" +Return type for `checkoutAttributesUpdate` mutation. +""" +type CheckoutAttributesUpdatePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Specifies the fields required to update a checkout's attributes. +""" +input CheckoutAttributesUpdateV2Input { + """ + The text of an optional note that a shop owner can attach to the checkout. + """ + note: String + + """ + A list of extra information that is added to the checkout. + """ + customAttributes: [AttributeInput!] + + """ + Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + The required attributes are city, province, and country. + Full validation of the addresses is still done at complete time. + """ + allowPartialAddresses: Boolean +} + +""" +Return type for `checkoutAttributesUpdateV2` mutation. +""" +type CheckoutAttributesUpdateV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteFree` mutation. +""" +type CheckoutCompleteFreePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithCreditCard` mutation. +""" +type CheckoutCompleteWithCreditCardPayload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithCreditCardV2` mutation. +""" +type CheckoutCompleteWithCreditCardV2Payload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithTokenizedPayment` mutation. +""" +type CheckoutCompleteWithTokenizedPaymentPayload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithTokenizedPaymentV2` mutation. +""" +type CheckoutCompleteWithTokenizedPaymentV2Payload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithTokenizedPaymentV3` mutation. +""" +type CheckoutCompleteWithTokenizedPaymentV3Payload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Specifies the fields required to create a checkout. +""" +input CheckoutCreateInput { + """ + The email with which the customer wants to checkout. + """ + email: String + + """ + A list of line item objects, each one containing information about an item in the checkout. + """ + lineItems: [CheckoutLineItemInput!] + + """ + The shipping address to where the line items will be shipped. + """ + shippingAddress: MailingAddressInput + + """ + The text of an optional note that a shop owner can attach to the checkout. + """ + note: String + + """ + A list of extra information that is added to the checkout. + """ + customAttributes: [AttributeInput!] + + """ + Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + The required attributes are city, province, and country. + Full validation of addresses is still done at complete time. + """ + allowPartialAddresses: Boolean + + """ + The three-letter currency code of one of the shop's enabled presentment currencies. + Including this field creates a checkout in the specified currency. By default, new + checkouts are created in the shop's primary currency. + """ + presentmentCurrencyCode: CurrencyCode +} + +""" +Return type for `checkoutCreate` mutation. +""" +type CheckoutCreatePayload { + """ + The new checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCustomerAssociate` mutation. +""" +type CheckoutCustomerAssociatePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + The associated customer object. + """ + customer: Customer + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! +} + +""" +Return type for `checkoutCustomerAssociateV2` mutation. +""" +type CheckoutCustomerAssociateV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + The associated customer object. + """ + customer: Customer + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCustomerDisassociate` mutation. +""" +type CheckoutCustomerDisassociatePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCustomerDisassociateV2` mutation. +""" +type CheckoutCustomerDisassociateV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutDiscountCodeApply` mutation. +""" +type CheckoutDiscountCodeApplyPayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutDiscountCodeApplyV2` mutation. +""" +type CheckoutDiscountCodeApplyV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutDiscountCodeRemove` mutation. +""" +type CheckoutDiscountCodeRemovePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutEmailUpdate` mutation. +""" +type CheckoutEmailUpdatePayload { + """ + The checkout object with the updated email. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutEmailUpdateV2` mutation. +""" +type CheckoutEmailUpdateV2Payload { + """ + The checkout object with the updated email. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Possible error codes that could be returned by CheckoutUserError. +""" +enum CheckoutErrorCode { + """ + Input value is blank. + """ + BLANK + + """ + Input value is invalid. + """ + INVALID + + """ + Input value is too long. + """ + TOO_LONG + + """ + Input value is not present. + """ + PRESENT + + """ + Input value should be less than maximum allowed value. + """ + LESS_THAN + + """ + Input value should be greater than or equal to minimum allowed value. + """ + GREATER_THAN_OR_EQUAL_TO + + """ + Input value should be less or equal to maximum allowed value. + """ + LESS_THAN_OR_EQUAL_TO + + """ + Checkout is already completed. + """ + ALREADY_COMPLETED + + """ + Checkout is locked. + """ + LOCKED + + """ + Input value is not supported. + """ + NOT_SUPPORTED + + """ + Input email contains an invalid domain name. + """ + BAD_DOMAIN + + """ + Input Zip is invalid for country provided. + """ + INVALID_FOR_COUNTRY + + """ + Input Zip is invalid for country and province provided. + """ + INVALID_FOR_COUNTRY_AND_PROVINCE + + """ + Invalid state in country. + """ + INVALID_STATE_IN_COUNTRY + + """ + Invalid province in country. + """ + INVALID_PROVINCE_IN_COUNTRY + + """ + Invalid region in country. + """ + INVALID_REGION_IN_COUNTRY + + """ + Shipping rate expired. + """ + SHIPPING_RATE_EXPIRED + + """ + Gift card cannot be applied to a checkout that contains a gift card. + """ + GIFT_CARD_UNUSABLE + + """ + Gift card is disabled. + """ + GIFT_CARD_DISABLED + + """ + Gift card code is invalid. + """ + GIFT_CARD_CODE_INVALID + + """ + Gift card has already been applied. + """ + GIFT_CARD_ALREADY_APPLIED + + """ + Gift card currency does not match checkout currency. + """ + GIFT_CARD_CURRENCY_MISMATCH + + """ + Gift card is expired. + """ + GIFT_CARD_EXPIRED + + """ + Gift card has no funds left. + """ + GIFT_CARD_DEPLETED + + """ + Gift card was not found. + """ + GIFT_CARD_NOT_FOUND + + """ + Cart does not meet discount requirements notice. + """ + CART_DOES_NOT_MEET_DISCOUNT_REQUIREMENTS_NOTICE + + """ + Discount expired. + """ + DISCOUNT_EXPIRED + + """ + Discount disabled. + """ + DISCOUNT_DISABLED + + """ + Discount limit reached. + """ + DISCOUNT_LIMIT_REACHED + + """ + Discount not found. + """ + DISCOUNT_NOT_FOUND + + """ + Customer already used once per customer discount notice. + """ + CUSTOMER_ALREADY_USED_ONCE_PER_CUSTOMER_DISCOUNT_NOTICE + + """ + Checkout is already completed. + """ + EMPTY + + """ + Not enough in stock. + """ + NOT_ENOUGH_IN_STOCK + + """ + Missing payment input. + """ + MISSING_PAYMENT_INPUT + + """ + The amount of the payment does not match the value to be paid. + """ + TOTAL_PRICE_MISMATCH + + """ + Line item was not found in checkout. + """ + LINE_ITEM_NOT_FOUND + + """ + Unable to apply discount. + """ + UNABLE_TO_APPLY + + """ + Discount already applied. + """ + DISCOUNT_ALREADY_APPLIED +} + +""" +Return type for `checkoutGiftCardApply` mutation. +""" +type CheckoutGiftCardApplyPayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutGiftCardRemove` mutation. +""" +type CheckoutGiftCardRemovePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutGiftCardRemoveV2` mutation. +""" +type CheckoutGiftCardRemoveV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutGiftCardsAppend` mutation. +""" +type CheckoutGiftCardsAppendPayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +A single line item in the checkout, grouped by variant and attributes. +""" +type CheckoutLineItem implements Node { + """ + Extra information in the form of an array of Key-Value pairs about the line item. + """ + customAttributes: [Attribute!]! + + """ + The discounts that have been allocated onto the checkout line item by discount applications. + """ + discountAllocations: [DiscountAllocation!]! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The quantity of the line item. + """ + quantity: Int! + + """ + Title of the line item. Defaults to the product's title. + """ + title: String! + + """ + Unit price of the line item. + """ + unitPrice: MoneyV2 + + """ + Product variant of the line item. + """ + variant: ProductVariant +} + +""" +An auto-generated type for paginating through multiple CheckoutLineItems. +""" +type CheckoutLineItemConnection { + """ + A list of edges. + """ + edges: [CheckoutLineItemEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one CheckoutLineItem and a cursor during pagination. +""" +type CheckoutLineItemEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of CheckoutLineItemEdge. + """ + node: CheckoutLineItem! +} + +""" +Specifies the input fields to create a line item on a checkout. +""" +input CheckoutLineItemInput { + """ + Extra information in the form of an array of Key-Value pairs about the line item. + """ + customAttributes: [AttributeInput!] + + """ + The quantity of the line item. + """ + quantity: Int! + + """ + The identifier of the product variant for the line item. + """ + variantId: ID! +} + +""" +Specifies the input fields to update a line item on the checkout. +""" +input CheckoutLineItemUpdateInput { + """ + The identifier of the line item. + """ + id: ID + + """ + The variant identifier of the line item. + """ + variantId: ID + + """ + The quantity of the line item. + """ + quantity: Int + + """ + Extra information in the form of an array of Key-Value pairs about the line item. + """ + customAttributes: [AttributeInput!] +} + +""" +Return type for `checkoutLineItemsAdd` mutation. +""" +type CheckoutLineItemsAddPayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutLineItemsRemove` mutation. +""" +type CheckoutLineItemsRemovePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutLineItemsReplace` mutation. +""" +type CheckoutLineItemsReplacePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [CheckoutUserError!]! +} + +""" +Return type for `checkoutLineItemsUpdate` mutation. +""" +type CheckoutLineItemsUpdatePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutShippingAddressUpdate` mutation. +""" +type CheckoutShippingAddressUpdatePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutShippingAddressUpdateV2` mutation. +""" +type CheckoutShippingAddressUpdateV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutShippingLineUpdate` mutation. +""" +type CheckoutShippingLineUpdatePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Represents an error that happens during execution of a checkout mutation. +""" +type CheckoutUserError implements DisplayableError { + """ + Error code to uniquely identify the error. + """ + code: CheckoutErrorCode + + """ + Path to the input field which caused the error. + """ + field: [String!] + + """ + The error message. + """ + message: String! +} + +""" +A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. +""" +type Collection implements Node { + """ + Stripped description of the collection, single line with HTML tags removed. + """ + description( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String! + + """ + The description of the collection, complete with HTML formatting. + """ + descriptionHtml: HTML! + + """ + A human-friendly unique string for the collection automatically generated from its title. + Limit of 255 characters. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + Image associated with the collection. + """ + image( + """ + Image width in pixels between 1 and 2048. This argument is deprecated: Use `maxWidth` on `Image.transformedSrc` instead. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 2048. This argument is deprecated: Use `maxHeight` on `Image.transformedSrc` instead. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. This argument is deprecated: Use `crop` on `Image.transformedSrc` instead. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. This argument is deprecated: Use `scale` on `Image.transformedSrc` instead. + """ + scale: Int = 1 + ): Image + + """ + List of products in the collection. + """ + products( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductCollectionSortKeys = COLLECTION_DEFAULT + ): ProductConnection! + + """ + The collection’s name. Limit of 255 characters. + """ + title: String! + + """ + The date and time when the collection was last modified. + """ + updatedAt: DateTime! +} + +""" +An auto-generated type for paginating through multiple Collections. +""" +type CollectionConnection { + """ + A list of edges. + """ + edges: [CollectionEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Collection and a cursor during pagination. +""" +type CollectionEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of CollectionEdge. + """ + node: Collection! +} + +""" +The set of valid sort keys for the Collection query. +""" +enum CollectionSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `updated_at` value. + """ + UPDATED_AT + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +A comment on an article. +""" +type Comment implements Node { + """ + The comment’s author. + """ + author: CommentAuthor! + + """ + Stripped content of the comment, single line with HTML tags removed. + """ + content( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String! + + """ + The content of the comment, complete with HTML formatting. + """ + contentHtml: HTML! + + """ + Globally unique identifier. + """ + id: ID! +} + +""" +The author of a comment. +""" +type CommentAuthor { + """ + The author's email. + """ + email: String! + + """ + The author’s name. + """ + name: String! +} + +""" +An auto-generated type for paginating through multiple Comments. +""" +type CommentConnection { + """ + A list of edges. + """ + edges: [CommentEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Comment and a cursor during pagination. +""" +type CommentEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of CommentEdge. + """ + node: Comment! +} + +""" +ISO 3166-1 alpha-2 country codes with some differences. +""" +enum CountryCode { + """ + Afghanistan. + """ + AF + + """ + Åland Islands. + """ + AX + + """ + Albania. + """ + AL + + """ + Algeria. + """ + DZ + + """ + Andorra. + """ + AD + + """ + Angola. + """ + AO + + """ + Anguilla. + """ + AI + + """ + Antigua & Barbuda. + """ + AG + + """ + Argentina. + """ + AR + + """ + Armenia. + """ + AM + + """ + Aruba. + """ + AW + + """ + Australia. + """ + AU + + """ + Austria. + """ + AT + + """ + Azerbaijan. + """ + AZ + + """ + Bahamas. + """ + BS + + """ + Bahrain. + """ + BH + + """ + Bangladesh. + """ + BD + + """ + Barbados. + """ + BB + + """ + Belarus. + """ + BY + + """ + Belgium. + """ + BE + + """ + Belize. + """ + BZ + + """ + Benin. + """ + BJ + + """ + Bermuda. + """ + BM + + """ + Bhutan. + """ + BT + + """ + Bolivia. + """ + BO + + """ + Bosnia & Herzegovina. + """ + BA + + """ + Botswana. + """ + BW + + """ + Bouvet Island. + """ + BV + + """ + Brazil. + """ + BR + + """ + British Indian Ocean Territory. + """ + IO + + """ + Brunei. + """ + BN + + """ + Bulgaria. + """ + BG + + """ + Burkina Faso. + """ + BF + + """ + Burundi. + """ + BI + + """ + Cambodia. + """ + KH + + """ + Canada. + """ + CA + + """ + Cape Verde. + """ + CV + + """ + Caribbean Netherlands. + """ + BQ + + """ + Cayman Islands. + """ + KY + + """ + Central African Republic. + """ + CF + + """ + Chad. + """ + TD + + """ + Chile. + """ + CL + + """ + China. + """ + CN + + """ + Christmas Island. + """ + CX + + """ + Cocos (Keeling) Islands. + """ + CC + + """ + Colombia. + """ + CO + + """ + Comoros. + """ + KM + + """ + Congo - Brazzaville. + """ + CG + + """ + Congo - Kinshasa. + """ + CD + + """ + Cook Islands. + """ + CK + + """ + Costa Rica. + """ + CR + + """ + Croatia. + """ + HR + + """ + Cuba. + """ + CU + + """ + Curaçao. + """ + CW + + """ + Cyprus. + """ + CY + + """ + Czechia. + """ + CZ + + """ + Côte d’Ivoire. + """ + CI + + """ + Denmark. + """ + DK + + """ + Djibouti. + """ + DJ + + """ + Dominica. + """ + DM + + """ + Dominican Republic. + """ + DO + + """ + Ecuador. + """ + EC + + """ + Egypt. + """ + EG + + """ + El Salvador. + """ + SV + + """ + Equatorial Guinea. + """ + GQ + + """ + Eritrea. + """ + ER + + """ + Estonia. + """ + EE + + """ + Eswatini. + """ + SZ + + """ + Ethiopia. + """ + ET + + """ + Falkland Islands. + """ + FK + + """ + Faroe Islands. + """ + FO + + """ + Fiji. + """ + FJ + + """ + Finland. + """ + FI + + """ + France. + """ + FR + + """ + French Guiana. + """ + GF + + """ + French Polynesia. + """ + PF + + """ + French Southern Territories. + """ + TF + + """ + Gabon. + """ + GA + + """ + Gambia. + """ + GM + + """ + Georgia. + """ + GE + + """ + Germany. + """ + DE + + """ + Ghana. + """ + GH + + """ + Gibraltar. + """ + GI + + """ + Greece. + """ + GR + + """ + Greenland. + """ + GL + + """ + Grenada. + """ + GD + + """ + Guadeloupe. + """ + GP + + """ + Guatemala. + """ + GT + + """ + Guernsey. + """ + GG + + """ + Guinea. + """ + GN + + """ + Guinea-Bissau. + """ + GW + + """ + Guyana. + """ + GY + + """ + Haiti. + """ + HT + + """ + Heard & McDonald Islands. + """ + HM + + """ + Vatican City. + """ + VA + + """ + Honduras. + """ + HN + + """ + Hong Kong SAR. + """ + HK + + """ + Hungary. + """ + HU + + """ + Iceland. + """ + IS + + """ + India. + """ + IN + + """ + Indonesia. + """ + ID + + """ + Iran. + """ + IR + + """ + Iraq. + """ + IQ + + """ + Ireland. + """ + IE + + """ + Isle of Man. + """ + IM + + """ + Israel. + """ + IL + + """ + Italy. + """ + IT + + """ + Jamaica. + """ + JM + + """ + Japan. + """ + JP + + """ + Jersey. + """ + JE + + """ + Jordan. + """ + JO + + """ + Kazakhstan. + """ + KZ + + """ + Kenya. + """ + KE + + """ + Kiribati. + """ + KI + + """ + North Korea. + """ + KP + + """ + Kosovo. + """ + XK + + """ + Kuwait. + """ + KW + + """ + Kyrgyzstan. + """ + KG + + """ + Laos. + """ + LA + + """ + Latvia. + """ + LV + + """ + Lebanon. + """ + LB + + """ + Lesotho. + """ + LS + + """ + Liberia. + """ + LR + + """ + Libya. + """ + LY + + """ + Liechtenstein. + """ + LI + + """ + Lithuania. + """ + LT + + """ + Luxembourg. + """ + LU + + """ + Macao SAR. + """ + MO + + """ + Madagascar. + """ + MG + + """ + Malawi. + """ + MW + + """ + Malaysia. + """ + MY + + """ + Maldives. + """ + MV + + """ + Mali. + """ + ML + + """ + Malta. + """ + MT + + """ + Martinique. + """ + MQ + + """ + Mauritania. + """ + MR + + """ + Mauritius. + """ + MU + + """ + Mayotte. + """ + YT + + """ + Mexico. + """ + MX + + """ + Moldova. + """ + MD + + """ + Monaco. + """ + MC + + """ + Mongolia. + """ + MN + + """ + Montenegro. + """ + ME + + """ + Montserrat. + """ + MS + + """ + Morocco. + """ + MA + + """ + Mozambique. + """ + MZ + + """ + Myanmar (Burma). + """ + MM + + """ + Namibia. + """ + NA + + """ + Nauru. + """ + NR + + """ + Nepal. + """ + NP + + """ + Netherlands. + """ + NL + + """ + Netherlands Antilles. + """ + AN + + """ + New Caledonia. + """ + NC + + """ + New Zealand. + """ + NZ + + """ + Nicaragua. + """ + NI + + """ + Niger. + """ + NE + + """ + Nigeria. + """ + NG + + """ + Niue. + """ + NU + + """ + Norfolk Island. + """ + NF + + """ + North Macedonia. + """ + MK + + """ + Norway. + """ + NO + + """ + Oman. + """ + OM + + """ + Pakistan. + """ + PK + + """ + Palestinian Territories. + """ + PS + + """ + Panama. + """ + PA + + """ + Papua New Guinea. + """ + PG + + """ + Paraguay. + """ + PY + + """ + Peru. + """ + PE + + """ + Philippines. + """ + PH + + """ + Pitcairn Islands. + """ + PN + + """ + Poland. + """ + PL + + """ + Portugal. + """ + PT + + """ + Qatar. + """ + QA + + """ + Cameroon. + """ + CM + + """ + Réunion. + """ + RE + + """ + Romania. + """ + RO + + """ + Russia. + """ + RU + + """ + Rwanda. + """ + RW + + """ + St. Barthélemy. + """ + BL + + """ + St. Helena. + """ + SH + + """ + St. Kitts & Nevis. + """ + KN + + """ + St. Lucia. + """ + LC + + """ + St. Martin. + """ + MF + + """ + St. Pierre & Miquelon. + """ + PM + + """ + Samoa. + """ + WS + + """ + San Marino. + """ + SM + + """ + São Tomé & Príncipe. + """ + ST + + """ + Saudi Arabia. + """ + SA + + """ + Senegal. + """ + SN + + """ + Serbia. + """ + RS + + """ + Seychelles. + """ + SC + + """ + Sierra Leone. + """ + SL + + """ + Singapore. + """ + SG + + """ + Sint Maarten. + """ + SX + + """ + Slovakia. + """ + SK + + """ + Slovenia. + """ + SI + + """ + Solomon Islands. + """ + SB + + """ + Somalia. + """ + SO + + """ + South Africa. + """ + ZA + + """ + South Georgia & South Sandwich Islands. + """ + GS + + """ + South Korea. + """ + KR + + """ + South Sudan. + """ + SS + + """ + Spain. + """ + ES + + """ + Sri Lanka. + """ + LK + + """ + St. Vincent & Grenadines. + """ + VC + + """ + Sudan. + """ + SD + + """ + Suriname. + """ + SR + + """ + Svalbard & Jan Mayen. + """ + SJ + + """ + Sweden. + """ + SE + + """ + Switzerland. + """ + CH + + """ + Syria. + """ + SY + + """ + Taiwan. + """ + TW + + """ + Tajikistan. + """ + TJ + + """ + Tanzania. + """ + TZ + + """ + Thailand. + """ + TH + + """ + Timor-Leste. + """ + TL + + """ + Togo. + """ + TG + + """ + Tokelau. + """ + TK + + """ + Tonga. + """ + TO + + """ + Trinidad & Tobago. + """ + TT + + """ + Tunisia. + """ + TN + + """ + Turkey. + """ + TR + + """ + Turkmenistan. + """ + TM + + """ + Turks & Caicos Islands. + """ + TC + + """ + Tuvalu. + """ + TV + + """ + Uganda. + """ + UG + + """ + Ukraine. + """ + UA + + """ + United Arab Emirates. + """ + AE + + """ + United Kingdom. + """ + GB + + """ + United States. + """ + US + + """ + U.S. Outlying Islands. + """ + UM + + """ + Uruguay. + """ + UY + + """ + Uzbekistan. + """ + UZ + + """ + Vanuatu. + """ + VU + + """ + Venezuela. + """ + VE + + """ + Vietnam. + """ + VN + + """ + British Virgin Islands. + """ + VG + + """ + Wallis & Futuna. + """ + WF + + """ + Western Sahara. + """ + EH + + """ + Yemen. + """ + YE + + """ + Zambia. + """ + ZM + + """ + Zimbabwe. + """ + ZW +} + +""" +Credit card information used for a payment. +""" +type CreditCard { + """ + The brand of the credit card. + """ + brand: String + + """ + The expiry month of the credit card. + """ + expiryMonth: Int + + """ + The expiry year of the credit card. + """ + expiryYear: Int + + """ + The credit card's BIN number. + """ + firstDigits: String + + """ + The first name of the card holder. + """ + firstName: String + + """ + The last 4 digits of the credit card. + """ + lastDigits: String + + """ + The last name of the card holder. + """ + lastName: String + + """ + The masked credit card number with only the last 4 digits displayed. + """ + maskedNumber: String +} + +""" +Specifies the fields required to complete a checkout with +a Shopify vaulted credit card payment. +""" +input CreditCardPaymentInput { + """ + The amount of the payment. + """ + amount: Money! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + The ID returned by Shopify's Card Vault. + """ + vaultId: String! + + """ + Executes the payment in test mode if possible. Defaults to `false`. + """ + test: Boolean +} + +""" +Specifies the fields required to complete a checkout with +a Shopify vaulted credit card payment. +""" +input CreditCardPaymentInputV2 { + """ + The amount and currency of the payment. + """ + paymentAmount: MoneyInput! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + The ID returned by Shopify's Card Vault. + """ + vaultId: String! + + """ + Executes the payment in test mode if possible. Defaults to `false`. + """ + test: Boolean +} + +""" +The part of the image that should remain after cropping. +""" +enum CropRegion { + """ + Keep the center of the image. + """ + CENTER + + """ + Keep the top of the image. + """ + TOP + + """ + Keep the bottom of the image. + """ + BOTTOM + + """ + Keep the left of the image. + """ + LEFT + + """ + Keep the right of the image. + """ + RIGHT +} + +""" +Currency codes. +""" +enum CurrencyCode { + """ + United States Dollars (USD). + """ + USD + + """ + Euro (EUR). + """ + EUR + + """ + United Kingdom Pounds (GBP). + """ + GBP + + """ + Canadian Dollars (CAD). + """ + CAD + + """ + Afghan Afghani (AFN). + """ + AFN + + """ + Albanian Lek (ALL). + """ + ALL + + """ + Algerian Dinar (DZD). + """ + DZD + + """ + Angolan Kwanza (AOA). + """ + AOA + + """ + Argentine Pesos (ARS). + """ + ARS + + """ + Armenian Dram (AMD). + """ + AMD + + """ + Aruban Florin (AWG). + """ + AWG + + """ + Australian Dollars (AUD). + """ + AUD + + """ + Barbadian Dollar (BBD). + """ + BBD + + """ + Azerbaijani Manat (AZN). + """ + AZN + + """ + Bangladesh Taka (BDT). + """ + BDT + + """ + Bahamian Dollar (BSD). + """ + BSD + + """ + Bahraini Dinar (BHD). + """ + BHD + + """ + Burundian Franc (BIF). + """ + BIF + + """ + Belarusian Ruble (BYN). + """ + BYN + + """ + Belarusian Ruble (BYR). + """ + BYR + + """ + Belize Dollar (BZD). + """ + BZD + + """ + Bermudian Dollar (BMD). + """ + BMD + + """ + Bhutanese Ngultrum (BTN). + """ + BTN + + """ + Bosnia and Herzegovina Convertible Mark (BAM). + """ + BAM + + """ + Brazilian Real (BRL). + """ + BRL + + """ + Bolivian Boliviano (BOB). + """ + BOB + + """ + Botswana Pula (BWP). + """ + BWP + + """ + Brunei Dollar (BND). + """ + BND + + """ + Bulgarian Lev (BGN). + """ + BGN + + """ + Burmese Kyat (MMK). + """ + MMK + + """ + Cambodian Riel. + """ + KHR + + """ + Cape Verdean escudo (CVE). + """ + CVE + + """ + Cayman Dollars (KYD). + """ + KYD + + """ + Central African CFA Franc (XAF). + """ + XAF + + """ + Chilean Peso (CLP). + """ + CLP + + """ + Chinese Yuan Renminbi (CNY). + """ + CNY + + """ + Colombian Peso (COP). + """ + COP + + """ + Comorian Franc (KMF). + """ + KMF + + """ + Congolese franc (CDF). + """ + CDF + + """ + Costa Rican Colones (CRC). + """ + CRC + + """ + Croatian Kuna (HRK). + """ + HRK + + """ + Czech Koruny (CZK). + """ + CZK + + """ + Danish Kroner (DKK). + """ + DKK + + """ + Djiboutian Franc (DJF). + """ + DJF + + """ + Dominican Peso (DOP). + """ + DOP + + """ + East Caribbean Dollar (XCD). + """ + XCD + + """ + Egyptian Pound (EGP). + """ + EGP + + """ + Eritrean Nakfa (ERN). + """ + ERN + + """ + Ethiopian Birr (ETB). + """ + ETB + + """ + Falkland Islands Pounds (FKP). + """ + FKP + + """ + CFP Franc (XPF). + """ + XPF + + """ + Fijian Dollars (FJD). + """ + FJD + + """ + Gibraltar Pounds (GIP). + """ + GIP + + """ + Gambian Dalasi (GMD). + """ + GMD + + """ + Ghanaian Cedi (GHS). + """ + GHS + + """ + Guatemalan Quetzal (GTQ). + """ + GTQ + + """ + Guyanese Dollar (GYD). + """ + GYD + + """ + Georgian Lari (GEL). + """ + GEL + + """ + Guinean Franc (GNF). + """ + GNF + + """ + Haitian Gourde (HTG). + """ + HTG + + """ + Honduran Lempira (HNL). + """ + HNL + + """ + Hong Kong Dollars (HKD). + """ + HKD + + """ + Hungarian Forint (HUF). + """ + HUF + + """ + Icelandic Kronur (ISK). + """ + ISK + + """ + Indian Rupees (INR). + """ + INR + + """ + Indonesian Rupiah (IDR). + """ + IDR + + """ + Israeli New Shekel (NIS). + """ + ILS + + """ + Iranian Rial (IRR). + """ + IRR + + """ + Iraqi Dinar (IQD). + """ + IQD + + """ + Jamaican Dollars (JMD). + """ + JMD + + """ + Japanese Yen (JPY). + """ + JPY + + """ + Jersey Pound. + """ + JEP + + """ + Jordanian Dinar (JOD). + """ + JOD + + """ + Kazakhstani Tenge (KZT). + """ + KZT + + """ + Kenyan Shilling (KES). + """ + KES + + """ + Kiribati Dollar (KID). + """ + KID + + """ + Kuwaiti Dinar (KWD). + """ + KWD + + """ + Kyrgyzstani Som (KGS). + """ + KGS + + """ + Laotian Kip (LAK). + """ + LAK + + """ + Latvian Lati (LVL). + """ + LVL + + """ + Lebanese Pounds (LBP). + """ + LBP + + """ + Lesotho Loti (LSL). + """ + LSL + + """ + Liberian Dollar (LRD). + """ + LRD + + """ + Libyan Dinar (LYD). + """ + LYD + + """ + Lithuanian Litai (LTL). + """ + LTL + + """ + Malagasy Ariary (MGA). + """ + MGA + + """ + Macedonia Denar (MKD). + """ + MKD + + """ + Macanese Pataca (MOP). + """ + MOP + + """ + Malawian Kwacha (MWK). + """ + MWK + + """ + Maldivian Rufiyaa (MVR). + """ + MVR + + """ + Mauritanian Ouguiya (MRU). + """ + MRU + + """ + Mexican Pesos (MXN). + """ + MXN + + """ + Malaysian Ringgits (MYR). + """ + MYR + + """ + Mauritian Rupee (MUR). + """ + MUR + + """ + Moldovan Leu (MDL). + """ + MDL + + """ + Moroccan Dirham. + """ + MAD + + """ + Mongolian Tugrik. + """ + MNT + + """ + Mozambican Metical. + """ + MZN + + """ + Namibian Dollar. + """ + NAD + + """ + Nepalese Rupee (NPR). + """ + NPR + + """ + Netherlands Antillean Guilder. + """ + ANG + + """ + New Zealand Dollars (NZD). + """ + NZD + + """ + Nicaraguan Córdoba (NIO). + """ + NIO + + """ + Nigerian Naira (NGN). + """ + NGN + + """ + Norwegian Kroner (NOK). + """ + NOK + + """ + Omani Rial (OMR). + """ + OMR + + """ + Panamian Balboa (PAB). + """ + PAB + + """ + Pakistani Rupee (PKR). + """ + PKR + + """ + Papua New Guinean Kina (PGK). + """ + PGK + + """ + Paraguayan Guarani (PYG). + """ + PYG + + """ + Peruvian Nuevo Sol (PEN). + """ + PEN + + """ + Philippine Peso (PHP). + """ + PHP + + """ + Polish Zlotych (PLN). + """ + PLN + + """ + Qatari Rial (QAR). + """ + QAR + + """ + Romanian Lei (RON). + """ + RON + + """ + Russian Rubles (RUB). + """ + RUB + + """ + Rwandan Franc (RWF). + """ + RWF + + """ + Samoan Tala (WST). + """ + WST + + """ + Saint Helena Pounds (SHP). + """ + SHP + + """ + Saudi Riyal (SAR). + """ + SAR + + """ + Sao Tome And Principe Dobra (STD). + """ + STD + + """ + Serbian dinar (RSD). + """ + RSD + + """ + Seychellois Rupee (SCR). + """ + SCR + + """ + Sierra Leonean Leone (SLL). + """ + SLL + + """ + Singapore Dollars (SGD). + """ + SGD + + """ + Sudanese Pound (SDG). + """ + SDG + + """ + Somali Shilling (SOS). + """ + SOS + + """ + Syrian Pound (SYP). + """ + SYP + + """ + South African Rand (ZAR). + """ + ZAR + + """ + South Korean Won (KRW). + """ + KRW + + """ + South Sudanese Pound (SSP). + """ + SSP + + """ + Solomon Islands Dollar (SBD). + """ + SBD + + """ + Sri Lankan Rupees (LKR). + """ + LKR + + """ + Surinamese Dollar (SRD). + """ + SRD + + """ + Swazi Lilangeni (SZL). + """ + SZL + + """ + Swedish Kronor (SEK). + """ + SEK + + """ + Swiss Francs (CHF). + """ + CHF + + """ + Taiwan Dollars (TWD). + """ + TWD + + """ + Thai baht (THB). + """ + THB + + """ + Tajikistani Somoni (TJS). + """ + TJS + + """ + Tanzanian Shilling (TZS). + """ + TZS + + """ + Tongan Pa'anga (TOP). + """ + TOP + + """ + Trinidad and Tobago Dollars (TTD). + """ + TTD + + """ + Tunisian Dinar (TND). + """ + TND + + """ + Turkish Lira (TRY). + """ + TRY + + """ + Turkmenistani Manat (TMT). + """ + TMT + + """ + Ugandan Shilling (UGX). + """ + UGX + + """ + Ukrainian Hryvnia (UAH). + """ + UAH + + """ + United Arab Emirates Dirham (AED). + """ + AED + + """ + Uruguayan Pesos (UYU). + """ + UYU + + """ + Uzbekistan som (UZS). + """ + UZS + + """ + Vanuatu Vatu (VUV). + """ + VUV + + """ + Venezuelan Bolivares (VEF). + """ + VEF + + """ + Venezuelan Bolivares (VES). + """ + VES + + """ + Vietnamese đồng (VND). + """ + VND + + """ + West African CFA franc (XOF). + """ + XOF + + """ + Yemeni Rial (YER). + """ + YER + + """ + Zambian Kwacha (ZMW). + """ + ZMW +} + +""" +A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. +""" +type Customer { + """ + Indicates whether the customer has consented to be sent marketing material via email. + """ + acceptsMarketing: Boolean! + + """ + A list of addresses for the customer. + """ + addresses( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MailingAddressConnection! + + """ + The date and time when the customer was created. + """ + createdAt: DateTime! + + """ + The customer’s default address. + """ + defaultAddress: MailingAddress + + """ + The customer’s name, email or phone number. + """ + displayName: String! + + """ + The customer’s email address. + """ + email: String + + """ + The customer’s first name. + """ + firstName: String + + """ + A unique identifier for the customer. + """ + id: ID! + + """ + The customer's most recently updated, incomplete checkout. + """ + lastIncompleteCheckout: Checkout + + """ + The customer’s last name. + """ + lastName: String + + """ + The orders associated with the customer. + """ + orders( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: OrderSortKeys = ID + + """ + Supported filter parameters: + - `processed_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): OrderConnection! + + """ + The customer’s phone number. + """ + phone: String + + """ + A comma separated list of tags that have been added to the customer. + Additional access scope required: unauthenticated_read_customer_tags. + """ + tags: [String!]! + + """ + The date and time when the customer information was updated. + """ + updatedAt: DateTime! +} + +""" +A CustomerAccessToken represents the unique token required to make modifications to the customer object. +""" +type CustomerAccessToken { + """ + The customer’s access token. + """ + accessToken: String! + + """ + The date and time when the customer access token expires. + """ + expiresAt: DateTime! +} + +""" +Specifies the input fields required to create a customer access token. +""" +input CustomerAccessTokenCreateInput { + """ + The email associated to the customer. + """ + email: String! + + """ + The login password to be used by the customer. + """ + password: String! +} + +""" +Return type for `customerAccessTokenCreate` mutation. +""" +type CustomerAccessTokenCreatePayload { + """ + The newly created customer access token object. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerAccessTokenCreateWithMultipass` mutation. +""" +type CustomerAccessTokenCreateWithMultipassPayload { + """ + An access token object associated with the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! +} + +""" +Return type for `customerAccessTokenDelete` mutation. +""" +type CustomerAccessTokenDeletePayload { + """ + The destroyed access token. + """ + deletedAccessToken: String + + """ + ID of the destroyed customer access token. + """ + deletedCustomerAccessTokenId: String + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! +} + +""" +Return type for `customerAccessTokenRenew` mutation. +""" +type CustomerAccessTokenRenewPayload { + """ + The renewed customer access token object. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! +} + +""" +Return type for `customerActivateByUrl` mutation. +""" +type CustomerActivateByUrlPayload { + """ + The customer that was activated. + """ + customer: Customer + + """ + A new customer access token for the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! +} + +""" +Specifies the input fields required to activate a customer. +""" +input CustomerActivateInput { + """ + The activation token required to activate the customer. + """ + activationToken: String! + + """ + New password that will be set during activation. + """ + password: String! +} + +""" +Return type for `customerActivate` mutation. +""" +type CustomerActivatePayload { + """ + The customer object. + """ + customer: Customer + + """ + A newly created customer access token object for the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerAddressCreate` mutation. +""" +type CustomerAddressCreatePayload { + """ + The new customer address object. + """ + customerAddress: MailingAddress + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerAddressDelete` mutation. +""" +type CustomerAddressDeletePayload { + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + ID of the deleted customer address. + """ + deletedCustomerAddressId: String + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerAddressUpdate` mutation. +""" +type CustomerAddressUpdatePayload { + """ + The customer’s updated mailing address. + """ + customerAddress: MailingAddress + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Specifies the fields required to create a new customer. +""" +input CustomerCreateInput { + """ + The customer’s first name. + """ + firstName: String + + """ + The customer’s last name. + """ + lastName: String + + """ + The customer’s email. + """ + email: String! + + """ + A unique phone number for the customer. + + Formatted using E.164 standard. For example, _+16135551111_. + """ + phone: String + + """ + The login password used by the customer. + """ + password: String! + + """ + Indicates whether the customer has consented to be sent marketing material via email. + """ + acceptsMarketing: Boolean +} + +""" +Return type for `customerCreate` mutation. +""" +type CustomerCreatePayload { + """ + The created customer object. + """ + customer: Customer + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerDefaultAddressUpdate` mutation. +""" +type CustomerDefaultAddressUpdatePayload { + """ + The updated customer object. + """ + customer: Customer + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Possible error codes that could be returned by CustomerUserError. +""" +enum CustomerErrorCode { + """ + Input value is blank. + """ + BLANK + + """ + Input value is invalid. + """ + INVALID + + """ + Input value is already taken. + """ + TAKEN + + """ + Input value is too long. + """ + TOO_LONG + + """ + Input value is too short. + """ + TOO_SHORT + + """ + Unidentified customer. + """ + UNIDENTIFIED_CUSTOMER + + """ + Customer is disabled. + """ + CUSTOMER_DISABLED + + """ + Input password starts or ends with whitespace. + """ + PASSWORD_STARTS_OR_ENDS_WITH_WHITESPACE + + """ + Input contains HTML tags. + """ + CONTAINS_HTML_TAGS + + """ + Input contains URL. + """ + CONTAINS_URL + + """ + Invalid activation token. + """ + TOKEN_INVALID + + """ + Customer already enabled. + """ + ALREADY_ENABLED + + """ + Address does not exist. + """ + NOT_FOUND + + """ + Input email contains an invalid domain name. + """ + BAD_DOMAIN + + """ + Multipass token is not valid. + """ + INVALID_MULTIPASS_REQUEST +} + +""" +Return type for `customerRecover` mutation. +""" +type CustomerRecoverPayload { + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerResetByUrl` mutation. +""" +type CustomerResetByUrlPayload { + """ + The customer object which was reset. + """ + customer: Customer + + """ + A newly created customer access token object for the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Specifies the fields required to reset a customer’s password. +""" +input CustomerResetInput { + """ + The reset token required to reset the customer’s password. + """ + resetToken: String! + + """ + New password that will be set as part of the reset password process. + """ + password: String! +} + +""" +Return type for `customerReset` mutation. +""" +type CustomerResetPayload { + """ + The customer object which was reset. + """ + customer: Customer + + """ + A newly created customer access token object for the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Specifies the fields required to update the Customer information. +""" +input CustomerUpdateInput { + """ + The customer’s first name. + """ + firstName: String + + """ + The customer’s last name. + """ + lastName: String + + """ + The customer’s email. + """ + email: String + + """ + A unique phone number for the customer. + + Formatted using E.164 standard. For example, _+16135551111_. To remove the phone number, specify `null`. + """ + phone: String + + """ + The login password used by the customer. + """ + password: String + + """ + Indicates whether the customer has consented to be sent marketing material via email. + """ + acceptsMarketing: Boolean +} + +""" +Return type for `customerUpdate` mutation. +""" +type CustomerUpdatePayload { + """ + The updated customer object. + """ + customer: Customer + + """ + The newly created customer access token. If the customer's password is updated, all previous access tokens + (including the one used to perform this mutation) become invalid, and a new token is generated. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Represents an error that happens during execution of a customer mutation. +""" +type CustomerUserError implements DisplayableError { + """ + Error code to uniquely identify the error. + """ + code: CustomerErrorCode + + """ + Path to the input field which caused the error. + """ + field: [String!] + + """ + The error message. + """ + message: String! +} + +""" +An ISO-8601 encoded UTC date time string. Example value: `"2019-07-03T20:47:55Z"`. +""" +scalar DateTime + +""" +A signed decimal number, which supports arbitrary precision and is serialized as a string. Example value: `"29.99"`. +""" +scalar Decimal + +""" +Digital wallet, such as Apple Pay, which can be used for accelerated checkouts. +""" +enum DigitalWallet { + """ + Apple Pay. + """ + APPLE_PAY + + """ + Android Pay. + """ + ANDROID_PAY + + """ + Google Pay. + """ + GOOGLE_PAY + + """ + Shopify Pay. + """ + SHOPIFY_PAY +} + +""" +An amount discounting the line that has been allocated by a discount. +""" +type DiscountAllocation { + """ + Amount of discount allocated. + """ + allocatedAmount: MoneyV2! + + """ + The discount this allocated amount originated from. + """ + discountApplication: DiscountApplication! +} + +""" +Discount applications capture the intentions of a discount source at +the time of application. +""" +interface DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +The method by which the discount's value is allocated onto its entitled lines. +""" +enum DiscountApplicationAllocationMethod { + """ + The value is spread across all entitled lines. + """ + ACROSS + + """ + The value is applied onto every entitled line. + """ + EACH + + """ + The value is specifically applied onto a particular line. + """ + ONE +} + +""" +An auto-generated type for paginating through multiple DiscountApplications. +""" +type DiscountApplicationConnection { + """ + A list of edges. + """ + edges: [DiscountApplicationEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one DiscountApplication and a cursor during pagination. +""" +type DiscountApplicationEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of DiscountApplicationEdge. + """ + node: DiscountApplication! +} + +""" +Which lines on the order that the discount is allocated over, of the type +defined by the Discount Application's target_type. +""" +enum DiscountApplicationTargetSelection { + """ + The discount is allocated onto all the lines. + """ + ALL + + """ + The discount is allocated onto only the lines it is entitled for. + """ + ENTITLED + + """ + The discount is allocated onto explicitly chosen lines. + """ + EXPLICIT +} + +""" +The type of line (i.e. line item or shipping line) on an order that the discount is applicable towards. +""" +enum DiscountApplicationTargetType { + """ + The discount applies onto line items. + """ + LINE_ITEM + + """ + The discount applies onto shipping lines. + """ + SHIPPING_LINE +} + +""" +Discount code applications capture the intentions of a discount code at +the time that it is applied. +""" +type DiscountCodeApplication implements DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + Specifies whether the discount code was applied successfully. + """ + applicable: Boolean! + + """ + The string identifying the discount code that was used at the time of application. + """ + code: String! + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +Represents an error in the input of a mutation. +""" +interface DisplayableError { + """ + Path to the input field which caused the error. + """ + field: [String!] + + """ + The error message. + """ + message: String! +} + +""" +Represents a web address. +""" +type Domain { + """ + The host name of the domain (eg: `example.com`). + """ + host: String! + + """ + Whether SSL is enabled or not. + """ + sslEnabled: Boolean! + + """ + The URL of the domain (eg: `https://example.com`). + """ + url: URL! +} + +""" +Represents a video hosted outside of Shopify. +""" +type ExternalVideo implements Node & Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + The URL. + """ + embeddedUrl: URL! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image +} + +""" +Represents a single fulfillment in an order. +""" +type Fulfillment { + """ + List of the fulfillment's line items. + """ + fulfillmentLineItems( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): FulfillmentLineItemConnection! + + """ + The name of the tracking company. + """ + trackingCompany: String + + """ + Tracking information associated with the fulfillment, + such as the tracking number and tracking URL. + """ + trackingInfo( + """ + Truncate the array result to this size. + """ + first: Int + ): [FulfillmentTrackingInfo!]! +} + +""" +Represents a single line item in a fulfillment. There is at most one fulfillment line item for each order line item. +""" +type FulfillmentLineItem { + """ + The associated order's line item. + """ + lineItem: OrderLineItem! + + """ + The amount fulfilled in this fulfillment. + """ + quantity: Int! +} + +""" +An auto-generated type for paginating through multiple FulfillmentLineItems. +""" +type FulfillmentLineItemConnection { + """ + A list of edges. + """ + edges: [FulfillmentLineItemEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one FulfillmentLineItem and a cursor during pagination. +""" +type FulfillmentLineItemEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of FulfillmentLineItemEdge. + """ + node: FulfillmentLineItem! +} + +""" +Tracking information associated with the fulfillment. +""" +type FulfillmentTrackingInfo { + """ + The tracking number of the fulfillment. + """ + number: String + + """ + The URL to track the fulfillment. + """ + url: URL +} + +""" +A string containing HTML code. Example value: `"<p>Grey cotton knit sweater.</p>"`. +""" +scalar HTML + +""" +Represents information about the metafields associated to the specified resource. +""" +interface HasMetafields { + """ + The metafield associated with the resource. + """ + metafield( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String! + + """ + Identifier for the metafield (maximum of 30 characters). + """ + key: String! + ): Metafield + + """ + A paginated list of metafields associated with the resource. + """ + metafields( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MetafieldConnection! +} + +""" +Represents an image resource. +""" +type Image { + """ + A word or phrase to share the nature or contents of an image. + """ + altText: String + + """ + The original height of the image in pixels. Returns `null` if the image is not hosted by Shopify. + """ + height: Int + + """ + A unique identifier for the image. + """ + id: ID + + """ + The location of the original image as a URL. + + If there are any existing transformations in the original source URL, they will remain and not be stripped. + """ + originalSrc: URL! + + """ + The location of the image as a URL. + """ + src: URL! + @deprecated( + reason: "Previously an image had a single `src` field. This could either return the original image\nlocation or a URL that contained transformations such as sizing or scale.\n\nThese transformations were specified by arguments on the parent field.\n\nNow an image has two distinct URL fields: `originalSrc` and `transformedSrc`.\n\n* `originalSrc` - the original unmodified image URL\n* `transformedSrc` - the image URL with the specified transformations included\n\nTo migrate to the new fields, image transformations should be moved from the parent field to `transformedSrc`.\n\nBefore:\n```graphql\n{\n shop {\n productImages(maxWidth: 200, scale: 2) {\n edges {\n node {\n src\n }\n }\n }\n }\n}\n```\n\nAfter:\n```graphql\n{\n shop {\n productImages {\n edges {\n node {\n transformedSrc(maxWidth: 200, scale: 2)\n }\n }\n }\n }\n}\n```\n" + ) + + """ + The location of the transformed image as a URL. + + All transformation arguments are considered "best-effort". If they can be applied to an image, they will be. + Otherwise any transformations which an image type does not support will be ignored. + """ + transformedSrc( + """ + Image width in pixels between 1 and 5760. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 5760. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. + """ + scale: Int = 1 + + """ + Best effort conversion of image into content type (SVG -> PNG, Anything -> JGP, Anything -> WEBP are supported). + """ + preferredContentType: ImageContentType + ): URL! + + """ + The original width of the image in pixels. Returns `null` if the image is not hosted by Shopify. + """ + width: Int +} + +""" +An auto-generated type for paginating through multiple Images. +""" +type ImageConnection { + """ + A list of edges. + """ + edges: [ImageEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +List of supported image content types. +""" +enum ImageContentType { + """ + A PNG image. + """ + PNG + + """ + A JPG image. + """ + JPG + + """ + A WEBP image. + """ + WEBP +} + +""" +An auto-generated type which holds one Image and a cursor during pagination. +""" +type ImageEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ImageEdge. + """ + node: Image! +} + +""" +Represents a mailing address for customers and shipping. +""" +type MailingAddress implements Node { + """ + The first line of the address. Typically the street address or PO Box number. + """ + address1: String + + """ + The second line of the address. Typically the number of the apartment, suite, or unit. + """ + address2: String + + """ + The name of the city, district, village, or town. + """ + city: String + + """ + The name of the customer's company or organization. + """ + company: String + + """ + The name of the country. + """ + country: String + + """ + The two-letter code for the country of the address. + + For example, US. + """ + countryCode: String @deprecated(reason: "Use `countryCodeV2` instead") + + """ + The two-letter code for the country of the address. + + For example, US. + """ + countryCodeV2: CountryCode + + """ + The first name of the customer. + """ + firstName: String + + """ + A formatted version of the address, customized by the provided arguments. + """ + formatted( + """ + Whether to include the customer's name in the formatted address. + """ + withName: Boolean = false + + """ + Whether to include the customer's company in the formatted address. + """ + withCompany: Boolean = true + ): [String!]! + + """ + A comma-separated list of the values for city, province, and country. + """ + formattedArea: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The last name of the customer. + """ + lastName: String + + """ + The latitude coordinate of the customer address. + """ + latitude: Float + + """ + The longitude coordinate of the customer address. + """ + longitude: Float + + """ + The full name of the customer, based on firstName and lastName. + """ + name: String + + """ + A unique phone number for the customer. + + Formatted using E.164 standard. For example, _+16135551111_. + """ + phone: String + + """ + The region of the address, such as the province, state, or district. + """ + province: String + + """ + The two-letter code for the region. + + For example, ON. + """ + provinceCode: String + + """ + The zip or postal code of the address. + """ + zip: String +} + +""" +An auto-generated type for paginating through multiple MailingAddresses. +""" +type MailingAddressConnection { + """ + A list of edges. + """ + edges: [MailingAddressEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one MailingAddress and a cursor during pagination. +""" +type MailingAddressEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of MailingAddressEdge. + """ + node: MailingAddress! +} + +""" +Specifies the fields accepted to create or update a mailing address. +""" +input MailingAddressInput { + """ + The first line of the address. Typically the street address or PO Box number. + """ + address1: String + + """ + The second line of the address. Typically the number of the apartment, suite, or unit. + """ + address2: String + + """ + The name of the city, district, village, or town. + """ + city: String + + """ + The name of the customer's company or organization. + """ + company: String + + """ + The name of the country. + """ + country: String + + """ + The first name of the customer. + """ + firstName: String + + """ + The last name of the customer. + """ + lastName: String + + """ + A unique phone number for the customer. + + Formatted using E.164 standard. For example, _+16135551111_. + """ + phone: String + + """ + The region of the address, such as the province, state, or district. + """ + province: String + + """ + The zip or postal code of the address. + """ + zip: String +} + +""" +Manual discount applications capture the intentions of a discount that was manually created. +""" +type ManualDiscountApplication implements DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + The description of the application. + """ + description: String + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The title of the application. + """ + title: String! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +Represents a media interface. +""" +interface Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image +} + +""" +An auto-generated type for paginating through multiple Media. +""" +type MediaConnection { + """ + A list of edges. + """ + edges: [MediaEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +The possible content types for a media object. +""" +enum MediaContentType { + """ + An externally hosted video. + """ + EXTERNAL_VIDEO + + """ + A Shopify hosted image. + """ + IMAGE + + """ + A 3d model. + """ + MODEL_3D + + """ + A Shopify hosted video. + """ + VIDEO +} + +""" +An auto-generated type which holds one Media and a cursor during pagination. +""" +type MediaEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of MediaEdge. + """ + node: Media! +} + +""" +Represents a Shopify hosted image. +""" +type MediaImage implements Node & Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The image for the media. + """ + image: Image + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image +} + +""" +Metafields represent custom metadata attached to a resource. Metafields can be sorted into namespaces and are +comprised of keys, values, and value types. +""" +type Metafield implements Node { + """ + The date and time when the storefront metafield was created. + """ + createdAt: DateTime! + + """ + The description of a metafield. + """ + description: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The key name for a metafield. + """ + key: String! + + """ + The namespace for a metafield. + """ + namespace: String! + + """ + The parent object that the metafield belongs to. + """ + parentResource: MetafieldParentResource! + + """ + The date and time when the storefront metafield was updated. + """ + updatedAt: DateTime! + + """ + The value of a metafield. + """ + value: String! + + """ + Represents the metafield value type. + """ + valueType: MetafieldValueType! +} + +""" +An auto-generated type for paginating through multiple Metafields. +""" +type MetafieldConnection { + """ + A list of edges. + """ + edges: [MetafieldEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Metafield and a cursor during pagination. +""" +type MetafieldEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of MetafieldEdge. + """ + node: Metafield! +} + +""" +A resource that the metafield belongs to. +""" +union MetafieldParentResource = Product | ProductVariant + +""" +Metafield value types. +""" +enum MetafieldValueType { + """ + A string metafield. + """ + STRING + + """ + An integer metafield. + """ + INTEGER + + """ + A json string metafield. + """ + JSON_STRING +} + +""" +Represents a Shopify hosted 3D model. +""" +type Model3d implements Node & Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image + + """ + The sources for a 3d model. + """ + sources: [Model3dSource!]! +} + +""" +Represents a source for a Shopify hosted 3d model. +""" +type Model3dSource { + """ + The filesize of the 3d model. + """ + filesize: Int! + + """ + The format of the 3d model. + """ + format: String! + + """ + The MIME type of the 3d model. + """ + mimeType: String! + + """ + The URL of the 3d model. + """ + url: String! +} + +""" +A monetary value string. Example value: `"100.57"`. +""" +scalar Money + +""" +Specifies the fields for a monetary value with currency. +""" +input MoneyInput { + """ + Decimal money amount. + """ + amount: Decimal! + + """ + Currency of the money. + """ + currencyCode: CurrencyCode! +} + +""" +A monetary value with currency. + +To format currencies, combine this type's amount and currencyCode fields with your client's locale. + +For example, in JavaScript you could use Intl.NumberFormat: + +```js +new Intl.NumberFormat(locale, { + style: 'currency', + currency: currencyCode +}).format(amount); +``` + +Other formatting libraries include: + +* iOS - [NumberFormatter](https://developer.apple.com/documentation/foundation/numberformatter) +* Android - [NumberFormat](https://developer.android.com/reference/java/text/NumberFormat.html) +* PHP - [NumberFormatter](http://php.net/manual/en/class.numberformatter.php) + +For a more general solution, the [Unicode CLDR number formatting database] is available with many implementations +(such as [TwitterCldr](https://github.com/twitter/twitter-cldr-rb)). +""" +type MoneyV2 { + """ + Decimal money amount. + """ + amount: Decimal! + + """ + Currency of the money. + """ + currencyCode: CurrencyCode! +} + +""" +An auto-generated type for paginating through multiple MoneyV2s. +""" +type MoneyV2Connection { + """ + A list of edges. + """ + edges: [MoneyV2Edge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one MoneyV2 and a cursor during pagination. +""" +type MoneyV2Edge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of MoneyV2Edge. + """ + node: MoneyV2! +} + +""" +The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. +""" +type Mutation { + """ + Updates the attributes of a checkout. + """ + checkoutAttributesUpdate( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The fields used to update a checkout's attributes. + """ + input: CheckoutAttributesUpdateInput! + ): CheckoutAttributesUpdatePayload + @deprecated(reason: "Use `checkoutAttributesUpdateV2` instead") + + """ + Updates the attributes of a checkout. + """ + checkoutAttributesUpdateV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The checkout attributes to update. + """ + input: CheckoutAttributesUpdateV2Input! + ): CheckoutAttributesUpdateV2Payload + + """ + Completes a checkout without providing payment information. You can use this mutation for free items or items whose purchase price is covered by a gift card. + """ + checkoutCompleteFree( + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutCompleteFreePayload + + """ + Completes a checkout using a credit card token from Shopify's Vault. + """ + checkoutCompleteWithCreditCard( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The credit card info to apply as a payment. + """ + payment: CreditCardPaymentInput! + ): CheckoutCompleteWithCreditCardPayload + @deprecated(reason: "Use `checkoutCompleteWithCreditCardV2` instead") + + """ + Completes a checkout using a credit card token from Shopify's card vault. Before you can complete checkouts using CheckoutCompleteWithCreditCardV2, you need to [_request payment processing_](https://help.shopify.com/api/guides/sales-channel-sdk/getting-started#request-payment-processing). + """ + checkoutCompleteWithCreditCardV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The credit card info to apply as a payment. + """ + payment: CreditCardPaymentInputV2! + ): CheckoutCompleteWithCreditCardV2Payload + + """ + Completes a checkout with a tokenized payment. + """ + checkoutCompleteWithTokenizedPayment( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The info to apply as a tokenized payment. + """ + payment: TokenizedPaymentInput! + ): CheckoutCompleteWithTokenizedPaymentPayload + @deprecated(reason: "Use `checkoutCompleteWithTokenizedPaymentV2` instead") + + """ + Completes a checkout with a tokenized payment. + """ + checkoutCompleteWithTokenizedPaymentV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The info to apply as a tokenized payment. + """ + payment: TokenizedPaymentInputV2! + ): CheckoutCompleteWithTokenizedPaymentV2Payload + @deprecated(reason: "Use `checkoutCompleteWithTokenizedPaymentV3` instead") + + """ + Completes a checkout with a tokenized payment. + """ + checkoutCompleteWithTokenizedPaymentV3( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The info to apply as a tokenized payment. + """ + payment: TokenizedPaymentInputV3! + ): CheckoutCompleteWithTokenizedPaymentV3Payload + + """ + Creates a new checkout. + """ + checkoutCreate( + """ + The fields used to create a checkout. + """ + input: CheckoutCreateInput! + ): CheckoutCreatePayload + + """ + Associates a customer to the checkout. + """ + checkoutCustomerAssociate( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The customer access token of the customer to associate. + """ + customerAccessToken: String! + ): CheckoutCustomerAssociatePayload + @deprecated(reason: "Use `checkoutCustomerAssociateV2` instead") + + """ + Associates a customer to the checkout. + """ + checkoutCustomerAssociateV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The customer access token of the customer to associate. + """ + customerAccessToken: String! + ): CheckoutCustomerAssociateV2Payload + + """ + Disassociates the current checkout customer from the checkout. + """ + checkoutCustomerDisassociate( + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutCustomerDisassociatePayload + @deprecated(reason: "Use `checkoutCustomerDisassociateV2` instead") + + """ + Disassociates the current checkout customer from the checkout. + """ + checkoutCustomerDisassociateV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutCustomerDisassociateV2Payload + + """ + Applies a discount to an existing checkout using a discount code. + """ + checkoutDiscountCodeApply( + """ + The discount code to apply to the checkout. + """ + discountCode: String! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutDiscountCodeApplyPayload + @deprecated(reason: "Use `checkoutDiscountCodeApplyV2` instead") + + """ + Applies a discount to an existing checkout using a discount code. + """ + checkoutDiscountCodeApplyV2( + """ + The discount code to apply to the checkout. + """ + discountCode: String! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutDiscountCodeApplyV2Payload + + """ + Removes the applied discount from an existing checkout. + """ + checkoutDiscountCodeRemove( + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutDiscountCodeRemovePayload + + """ + Updates the email on an existing checkout. + """ + checkoutEmailUpdate( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The email to update the checkout with. + """ + email: String! + ): CheckoutEmailUpdatePayload + @deprecated(reason: "Use `checkoutEmailUpdateV2` instead") + + """ + Updates the email on an existing checkout. + """ + checkoutEmailUpdateV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The email to update the checkout with. + """ + email: String! + ): CheckoutEmailUpdateV2Payload + + """ + Applies a gift card to an existing checkout using a gift card code. This will replace all currently applied gift cards. + """ + checkoutGiftCardApply( + """ + The code of the gift card to apply on the checkout. + """ + giftCardCode: String! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutGiftCardApplyPayload + @deprecated(reason: "Use `checkoutGiftCardsAppend` instead") + + """ + Removes an applied gift card from the checkout. + """ + checkoutGiftCardRemove( + """ + The ID of the Applied Gift Card to remove from the Checkout. + """ + appliedGiftCardId: ID! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutGiftCardRemovePayload + @deprecated(reason: "Use `checkoutGiftCardRemoveV2` instead") + + """ + Removes an applied gift card from the checkout. + """ + checkoutGiftCardRemoveV2( + """ + The ID of the Applied Gift Card to remove from the Checkout. + """ + appliedGiftCardId: ID! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutGiftCardRemoveV2Payload + + """ + Appends gift cards to an existing checkout. + """ + checkoutGiftCardsAppend( + """ + A list of gift card codes to append to the checkout. + """ + giftCardCodes: [String!]! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutGiftCardsAppendPayload + + """ + Adds a list of line items to a checkout. + """ + checkoutLineItemsAdd( + """ + A list of line item objects to add to the checkout. + """ + lineItems: [CheckoutLineItemInput!]! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutLineItemsAddPayload + + """ + Removes line items from an existing checkout. + """ + checkoutLineItemsRemove( + """ + The checkout on which to remove line items. + """ + checkoutId: ID! + + """ + Line item ids to remove. + """ + lineItemIds: [ID!]! + ): CheckoutLineItemsRemovePayload + + """ + Sets a list of line items to a checkout. + """ + checkoutLineItemsReplace( + """ + A list of line item objects to set on the checkout. + """ + lineItems: [CheckoutLineItemInput!]! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutLineItemsReplacePayload + + """ + Updates line items on a checkout. + """ + checkoutLineItemsUpdate( + """ + The checkout on which to update line items. + """ + checkoutId: ID! + + """ + Line items to update. + """ + lineItems: [CheckoutLineItemUpdateInput!]! + ): CheckoutLineItemsUpdatePayload + + """ + Updates the shipping address of an existing checkout. + """ + checkoutShippingAddressUpdate( + """ + The shipping address to where the line items will be shipped. + """ + shippingAddress: MailingAddressInput! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutShippingAddressUpdatePayload + @deprecated(reason: "Use `checkoutShippingAddressUpdateV2` instead") + + """ + Updates the shipping address of an existing checkout. + """ + checkoutShippingAddressUpdateV2( + """ + The shipping address to where the line items will be shipped. + """ + shippingAddress: MailingAddressInput! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutShippingAddressUpdateV2Payload + + """ + Updates the shipping lines on an existing checkout. + """ + checkoutShippingLineUpdate( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + A unique identifier to a Checkout’s shipping provider, price, and title combination, enabling the customer to select the availableShippingRates. + """ + shippingRateHandle: String! + ): CheckoutShippingLineUpdatePayload + + """ + Creates a customer access token. + The customer access token is required to modify the customer object in any way. + """ + customerAccessTokenCreate( + """ + The fields used to create a customer access token. + """ + input: CustomerAccessTokenCreateInput! + ): CustomerAccessTokenCreatePayload + + """ + Creates a customer access token using a multipass token instead of email and password. + A customer record is created if customer does not exist. If a customer record already + exists but the record is disabled, then it's enabled. + """ + customerAccessTokenCreateWithMultipass( + """ + A valid multipass token to be authenticated. + """ + multipassToken: String! + ): CustomerAccessTokenCreateWithMultipassPayload + + """ + Permanently destroys a customer access token. + """ + customerAccessTokenDelete( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + ): CustomerAccessTokenDeletePayload + + """ + Renews a customer access token. + + Access token renewal must happen *before* a token expires. + If a token has already expired, a new one should be created instead via `customerAccessTokenCreate`. + """ + customerAccessTokenRenew( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + ): CustomerAccessTokenRenewPayload + + """ + Activates a customer. + """ + customerActivate( + """ + Specifies the customer to activate. + """ + id: ID! + + """ + The fields used to activate a customer. + """ + input: CustomerActivateInput! + ): CustomerActivatePayload + + """ + Activates a customer with the activation url received from `customerCreate`. + """ + customerActivateByUrl( + """ + The customer activation URL. + """ + activationUrl: URL! + + """ + A new password set during activation. + """ + password: String! + ): CustomerActivateByUrlPayload + + """ + Creates a new address for a customer. + """ + customerAddressCreate( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + + """ + The customer mailing address to create. + """ + address: MailingAddressInput! + ): CustomerAddressCreatePayload + + """ + Permanently deletes the address of an existing customer. + """ + customerAddressDelete( + """ + Specifies the address to delete. + """ + id: ID! + + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + ): CustomerAddressDeletePayload + + """ + Updates the address of an existing customer. + """ + customerAddressUpdate( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + + """ + Specifies the customer address to update. + """ + id: ID! + + """ + The customer’s mailing address. + """ + address: MailingAddressInput! + ): CustomerAddressUpdatePayload + + """ + Creates a new customer. + """ + customerCreate( + """ + The fields used to create a new customer. + """ + input: CustomerCreateInput! + ): CustomerCreatePayload + + """ + Updates the default address of an existing customer. + """ + customerDefaultAddressUpdate( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + + """ + ID of the address to set as the new default for the customer. + """ + addressId: ID! + ): CustomerDefaultAddressUpdatePayload + + """ + Sends a reset password email to the customer, as the first step in the reset password process. + """ + customerRecover( + """ + The email address of the customer to recover. + """ + email: String! + ): CustomerRecoverPayload + + """ + Resets a customer’s password with a token received from `CustomerRecover`. + """ + customerReset( + """ + Specifies the customer to reset. + """ + id: ID! + + """ + The fields used to reset a customer’s password. + """ + input: CustomerResetInput! + ): CustomerResetPayload + + """ + Resets a customer’s password with the reset password url received from `CustomerRecover`. + """ + customerResetByUrl( + """ + The customer's reset password url. + """ + resetUrl: URL! + + """ + New password that will be set as part of the reset password process. + """ + password: String! + ): CustomerResetByUrlPayload + + """ + Updates an existing customer. + """ + customerUpdate( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + + """ + The customer object input. + """ + customer: CustomerUpdateInput! + ): CustomerUpdatePayload +} + +""" +An object with an ID to support global identification. +""" +interface Node { + """ + Globally unique identifier. + """ + id: ID! +} + +""" +An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. +""" +type Order implements Node { + """ + The reason for the order's cancellation. Returns `null` if the order wasn't canceled. + """ + cancelReason: OrderCancelReason + + """ + The date and time when the order was canceled. Returns null if the order wasn't canceled. + """ + canceledAt: DateTime + + """ + The code of the currency used for the payment. + """ + currencyCode: CurrencyCode! + + """ + The subtotal of line items and their discounts, excluding line items that have been removed. Does not contain order-level discounts, duties, shipping costs, or shipping discounts. Taxes are not included unless the order is a taxes-included order. + """ + currentSubtotalPrice: MoneyV2! + + """ + The total amount of the order, including duties, taxes and discounts, minus amounts for line items that have been removed. + """ + currentTotalPrice: MoneyV2! + + """ + The total of all taxes applied to the order, excluding taxes for returned line items. + """ + currentTotalTax: MoneyV2! + + """ + The locale code in which this specific order happened. + """ + customerLocale: String + + """ + The unique URL that the customer can use to access the order. + """ + customerUrl: URL + + """ + Discounts that have been applied on the order. + """ + discountApplications( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): DiscountApplicationConnection! + + """ + Whether the order has had any edits applied or not. + """ + edited: Boolean! + + """ + The customer's email address. + """ + email: String + + """ + The financial status of the order. + """ + financialStatus: OrderFinancialStatus + + """ + The fulfillment status for the order. + """ + fulfillmentStatus: OrderFulfillmentStatus! + + """ + Globally unique identifier. + """ + id: ID! + + """ + List of the order’s line items. + """ + lineItems( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): OrderLineItemConnection! + + """ + Unique identifier for the order that appears on the order. + For example, _#1000_ or _Store1001. + """ + name: String! + + """ + A unique numeric identifier for the order for use by shop owner and customer. + """ + orderNumber: Int! + + """ + The total price of the order before any applied edits. + """ + originalTotalPrice: MoneyV2! + + """ + The customer's phone number for receiving SMS notifications. + """ + phone: String + + """ + The date and time when the order was imported. + This value can be set to dates in the past when importing from other systems. + If no value is provided, it will be auto-generated based on current date and time. + """ + processedAt: DateTime! + + """ + The address to where the order will be shipped. + """ + shippingAddress: MailingAddress + + """ + The discounts that have been allocated onto the shipping line by discount applications. + """ + shippingDiscountAllocations: [DiscountAllocation!]! + + """ + The unique URL for the order's status page. + """ + statusUrl: URL! + + """ + Price of the order before shipping and taxes. + """ + subtotalPrice: Money @deprecated(reason: "Use `subtotalPriceV2` instead") + + """ + Price of the order before duties, shipping and taxes. + """ + subtotalPriceV2: MoneyV2 + + """ + List of the order’s successful fulfillments. + """ + successfulFulfillments( + """ + Truncate the array result to this size. + """ + first: Int + ): [Fulfillment!] + + """ + The sum of all the prices of all the items in the order, taxes and discounts included (must be positive). + """ + totalPrice: Money! @deprecated(reason: "Use `totalPriceV2` instead") + + """ + The sum of all the prices of all the items in the order, duties, taxes and discounts included (must be positive). + """ + totalPriceV2: MoneyV2! + + """ + The total amount that has been refunded. + """ + totalRefunded: Money! @deprecated(reason: "Use `totalRefundedV2` instead") + + """ + The total amount that has been refunded. + """ + totalRefundedV2: MoneyV2! + + """ + The total cost of shipping. + """ + totalShippingPrice: Money! + @deprecated(reason: "Use `totalShippingPriceV2` instead") + + """ + The total cost of shipping. + """ + totalShippingPriceV2: MoneyV2! + + """ + The total cost of taxes. + """ + totalTax: Money @deprecated(reason: "Use `totalTaxV2` instead") + + """ + The total cost of taxes. + """ + totalTaxV2: MoneyV2 +} + +""" +Represents the reason for the order's cancellation. +""" +enum OrderCancelReason { + """ + The customer wanted to cancel the order. + """ + CUSTOMER + + """ + The order was fraudulent. + """ + FRAUD + + """ + There was insufficient inventory. + """ + INVENTORY + + """ + Payment was declined. + """ + DECLINED + + """ + The order was canceled for an unlisted reason. + """ + OTHER +} + +""" +An auto-generated type for paginating through multiple Orders. +""" +type OrderConnection { + """ + A list of edges. + """ + edges: [OrderEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Order and a cursor during pagination. +""" +type OrderEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of OrderEdge. + """ + node: Order! +} + +""" +Represents the order's current financial status. +""" +enum OrderFinancialStatus { + """ + Displayed as **Pending**. + """ + PENDING + + """ + Displayed as **Authorized**. + """ + AUTHORIZED + + """ + Displayed as **Partially paid**. + """ + PARTIALLY_PAID + + """ + Displayed as **Partially refunded**. + """ + PARTIALLY_REFUNDED + + """ + Displayed as **Voided**. + """ + VOIDED + + """ + Displayed as **Paid**. + """ + PAID + + """ + Displayed as **Refunded**. + """ + REFUNDED +} + +""" +Represents the order's current fulfillment status. +""" +enum OrderFulfillmentStatus { + """ + Displayed as **Unfulfilled**. + """ + UNFULFILLED + + """ + Displayed as **Partially fulfilled**. + """ + PARTIALLY_FULFILLED + + """ + Displayed as **Fulfilled**. + """ + FULFILLED + + """ + Displayed as **Restocked**. + """ + RESTOCKED + + """ + Displayed as **Pending fulfillment**. + """ + PENDING_FULFILLMENT + + """ + Displayed as **Open**. + """ + OPEN + + """ + Displayed as **In progress**. + """ + IN_PROGRESS + + """ + Displayed as **Scheduled**. + """ + SCHEDULED +} + +""" +Represents a single line in an order. There is one line item for each distinct product variant. +""" +type OrderLineItem { + """ + The number of entries associated to the line item minus the items that have been removed. + """ + currentQuantity: Int! + + """ + List of custom attributes associated to the line item. + """ + customAttributes: [Attribute!]! + + """ + The discounts that have been allocated onto the order line item by discount applications. + """ + discountAllocations: [DiscountAllocation!]! + + """ + The total price of the line item, including discounts, and displayed in the presentment currency. + """ + discountedTotalPrice: MoneyV2! + + """ + The total price of the line item, not including any discounts. The total price is calculated using the original unit price multiplied by the quantity, and it is displayed in the presentment currency. + """ + originalTotalPrice: MoneyV2! + + """ + The number of products variants associated to the line item. + """ + quantity: Int! + + """ + The title of the product combined with title of the variant. + """ + title: String! + + """ + The product variant object associated to the line item. + """ + variant: ProductVariant +} + +""" +An auto-generated type for paginating through multiple OrderLineItems. +""" +type OrderLineItemConnection { + """ + A list of edges. + """ + edges: [OrderLineItemEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one OrderLineItem and a cursor during pagination. +""" +type OrderLineItemEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of OrderLineItemEdge. + """ + node: OrderLineItem! +} + +""" +The set of valid sort keys for the Order query. +""" +enum OrderSortKeys { + """ + Sort by the `processed_at` value. + """ + PROCESSED_AT + + """ + Sort by the `total_price` value. + """ + TOTAL_PRICE + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +Shopify merchants can create pages to hold static HTML content. Each Page object represents a custom page on the online store. +""" +type Page implements Node { + """ + The description of the page, complete with HTML formatting. + """ + body: HTML! + + """ + Summary of the page body. + """ + bodySummary: String! + + """ + The timestamp of the page creation. + """ + createdAt: DateTime! + + """ + A human-friendly unique string for the page automatically generated from its title. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The page's SEO information. + """ + seo: SEO + + """ + The title of the page. + """ + title: String! + + """ + The timestamp of the latest page update. + """ + updatedAt: DateTime! + + """ + The url pointing to the page accessible from the web. + """ + url: URL! +} + +""" +An auto-generated type for paginating through multiple Pages. +""" +type PageConnection { + """ + A list of edges. + """ + edges: [PageEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Page and a cursor during pagination. +""" +type PageEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of PageEdge. + """ + node: Page! +} + +""" +Information about pagination in a connection. +""" +type PageInfo { + """ + Indicates if there are more pages to fetch. + """ + hasNextPage: Boolean! + + """ + Indicates if there are any pages prior to the current page. + """ + hasPreviousPage: Boolean! +} + +""" +The set of valid sort keys for the Page query. +""" +enum PageSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `updated_at` value. + """ + UPDATED_AT + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +A payment applied to a checkout. +""" +type Payment implements Node { + """ + The amount of the payment. + """ + amount: Money! @deprecated(reason: "Use `amountV2` instead") + + """ + The amount of the payment. + """ + amountV2: MoneyV2! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddress + + """ + The checkout to which the payment belongs. + """ + checkout: Checkout! + + """ + The credit card used for the payment in the case of direct payments. + """ + creditCard: CreditCard + + """ + A message describing a processing error during asynchronous processing. + """ + errorMessage: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + A client-side generated token to identify a payment and perform idempotent operations. + """ + idempotencyKey: String + + """ + The URL where the customer needs to be redirected so they can complete the 3D Secure payment flow. + """ + nextActionUrl: URL + + """ + Whether or not the payment is still processing asynchronously. + """ + ready: Boolean! + + """ + A flag to indicate if the payment is to be done in test mode for gateways that support it. + """ + test: Boolean! + + """ + The actual transaction recorded by Shopify after having processed the payment with the gateway. + """ + transaction: Transaction +} + +""" +Settings related to payments. +""" +type PaymentSettings { + """ + List of the card brands which the shop accepts. + """ + acceptedCardBrands: [CardBrand!]! + + """ + The url pointing to the endpoint to vault credit cards. + """ + cardVaultUrl: URL! + + """ + The country where the shop is located. + """ + countryCode: CountryCode! + + """ + The three-letter code for the shop's primary currency. + """ + currencyCode: CurrencyCode! + + """ + A list of enabled currencies (ISO 4217 format) that the shop accepts. Merchants can enable currencies from their Shopify Payments settings in the Shopify admin. + """ + enabledPresentmentCurrencies: [CurrencyCode!]! + + """ + The shop’s Shopify Payments account id. + """ + shopifyPaymentsAccountId: String + + """ + List of the digital wallets which the shop supports. + """ + supportedDigitalWallets: [DigitalWallet!]! +} + +""" +The valid values for the types of payment token. +""" +enum PaymentTokenType { + """ + Apple Pay token type. + """ + APPLE_PAY + + """ + Vault payment token type. + """ + VAULT + + """ + Shopify Pay token type. + """ + SHOPIFY_PAY + + """ + Google Pay token type. + """ + GOOGLE_PAY +} + +""" +The value of the percentage pricing object. +""" +type PricingPercentageValue { + """ + The percentage value of the object. + """ + percentage: Float! +} + +""" +The price value (fixed or percentage) for a discount application. +""" +union PricingValue = MoneyV2 | PricingPercentageValue + +""" +A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. +For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). +""" +type Product implements Node & HasMetafields { + """ + Indicates if at least one product variant is available for sale. + """ + availableForSale: Boolean! + + """ + List of collections a product belongs to. + """ + collections( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): CollectionConnection! + + """ + The compare at price of the product across all variants. + """ + compareAtPriceRange: ProductPriceRange! + + """ + The date and time when the product was created. + """ + createdAt: DateTime! + + """ + Stripped description of the product, single line with HTML tags removed. + """ + description( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String! + + """ + The description of the product, complete with HTML formatting. + """ + descriptionHtml: HTML! + + """ + A human-friendly unique string for the Product automatically generated from its title. + They are used by the Liquid templating language to refer to objects. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + List of images associated with the product. + """ + images( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductImageSortKeys = POSITION + + """ + Image width in pixels between 1 and 2048. This argument is deprecated: Use `maxWidth` on `Image.transformedSrc` instead. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 2048. This argument is deprecated: Use `maxHeight` on `Image.transformedSrc` instead. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. This argument is deprecated: Use `crop` on `Image.transformedSrc` instead. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. This argument is deprecated: Use `scale` on `Image.transformedSrc` instead. + """ + scale: Int = 1 + ): ImageConnection! + + """ + The media associated with the product. + """ + media( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductMediaSortKeys = POSITION + ): MediaConnection! + + """ + The metafield associated with the resource. + """ + metafield( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String! + + """ + Identifier for the metafield (maximum of 30 characters). + """ + key: String! + ): Metafield + + """ + A paginated list of metafields associated with the resource. + """ + metafields( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MetafieldConnection! + + """ + The online store URL for the product. + A value of `null` indicates that the product is not published to the Online Store sales channel. + """ + onlineStoreUrl: URL + + """ + List of product options. + """ + options( + """ + Truncate the array result to this size. + """ + first: Int + ): [ProductOption!]! + + """ + List of price ranges in the presentment currencies for this shop. + """ + presentmentPriceRanges( + """ + Specifies the presentment currencies to return a price range in. + """ + presentmentCurrencies: [CurrencyCode!] + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): ProductPriceRangeConnection! + + """ + The price range. + """ + priceRange: ProductPriceRange! + + """ + A categorization that a product can be tagged with, commonly used for filtering and searching. + """ + productType: String! + + """ + The date and time when the product was published to the channel. + """ + publishedAt: DateTime! + + """ + The product's SEO information. + """ + seo: SEO! + + """ + A comma separated list of tags that have been added to the product. + Additional access scope required for private apps: unauthenticated_read_product_tags. + """ + tags: [String!]! + + """ + The product’s title. + """ + title: String! + + """ + The total quantity of inventory in stock for this Product. + """ + totalInventory: Int + + """ + The date and time when the product was last modified. + A product's `updatedAt` value can change for different reasons. For example, if an order + is placed for a product that has inventory tracking set up, then the inventory adjustment + is counted as an update. + """ + updatedAt: DateTime! + + """ + Find a product’s variant based on its selected options. + This is useful for converting a user’s selection of product options into a single matching variant. + If there is not a variant for the selected options, `null` will be returned. + """ + variantBySelectedOptions( + """ + The input fields used for a selected option. + """ + selectedOptions: [SelectedOptionInput!]! + ): ProductVariant + + """ + List of the product’s variants. + """ + variants( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductVariantSortKeys = POSITION + ): ProductVariantConnection! + + """ + The product’s vendor name. + """ + vendor: String! +} + +""" +The set of valid sort keys for the ProductCollection query. +""" +enum ProductCollectionSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `price` value. + """ + PRICE + + """ + Sort by the `best-selling` value. + """ + BEST_SELLING + + """ + Sort by the `created` value. + """ + CREATED + + """ + Sort by the `id` value. + """ + ID + + """ + Sort by the `manual` value. + """ + MANUAL + + """ + Sort by the `collection-default` value. + """ + COLLECTION_DEFAULT + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +An auto-generated type for paginating through multiple Products. +""" +type ProductConnection { + """ + A list of edges. + """ + edges: [ProductEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Product and a cursor during pagination. +""" +type ProductEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ProductEdge. + """ + node: Product! +} + +""" +The set of valid sort keys for the ProductImage query. +""" +enum ProductImageSortKeys { + """ + Sort by the `created_at` value. + """ + CREATED_AT + + """ + Sort by the `position` value. + """ + POSITION + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +The set of valid sort keys for the ProductMedia query. +""" +enum ProductMediaSortKeys { + """ + Sort by the `position` value. + """ + POSITION + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +Product property names like "Size", "Color", and "Material" that the customers can select. +Variants are selected based on permutations of these options. +255 characters limit each. +""" +type ProductOption implements Node { + """ + Globally unique identifier. + """ + id: ID! + + """ + The product option’s name. + """ + name: String! + + """ + The corresponding value to the product option name. + """ + values: [String!]! +} + +""" +The price range of the product. +""" +type ProductPriceRange { + """ + The highest variant's price. + """ + maxVariantPrice: MoneyV2! + + """ + The lowest variant's price. + """ + minVariantPrice: MoneyV2! +} + +""" +An auto-generated type for paginating through multiple ProductPriceRanges. +""" +type ProductPriceRangeConnection { + """ + A list of edges. + """ + edges: [ProductPriceRangeEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one ProductPriceRange and a cursor during pagination. +""" +type ProductPriceRangeEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ProductPriceRangeEdge. + """ + node: ProductPriceRange! +} + +""" +The set of valid sort keys for the Product query. +""" +enum ProductSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `product_type` value. + """ + PRODUCT_TYPE + + """ + Sort by the `vendor` value. + """ + VENDOR + + """ + Sort by the `updated_at` value. + """ + UPDATED_AT + + """ + Sort by the `created_at` value. + """ + CREATED_AT + + """ + Sort by the `best_selling` value. + """ + BEST_SELLING + + """ + Sort by the `price` value. + """ + PRICE + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +A product variant represents a different version of a product, such as differing sizes or differing colors. +""" +type ProductVariant implements Node & HasMetafields { + """ + Indicates if the product variant is in stock. + """ + available: Boolean @deprecated(reason: "Use `availableForSale` instead") + + """ + Indicates if the product variant is available for sale. + """ + availableForSale: Boolean! + + """ + The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPrice` is higher than `price`. + """ + compareAtPrice: Money @deprecated(reason: "Use `compareAtPriceV2` instead") + + """ + The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPriceV2` is higher than `priceV2`. + """ + compareAtPriceV2: MoneyV2 + + """ + Whether a product is out of stock but still available for purchase (used for backorders). + """ + currentlyNotInStock: Boolean! + + """ + Globally unique identifier. + """ + id: ID! + + """ + Image associated with the product variant. This field falls back to the product image if no image is available. + """ + image( + """ + Image width in pixels between 1 and 2048. This argument is deprecated: Use `maxWidth` on `Image.transformedSrc` instead. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 2048. This argument is deprecated: Use `maxHeight` on `Image.transformedSrc` instead. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. This argument is deprecated: Use `crop` on `Image.transformedSrc` instead. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. This argument is deprecated: Use `scale` on `Image.transformedSrc` instead. + """ + scale: Int = 1 + ): Image + + """ + The metafield associated with the resource. + """ + metafield( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String! + + """ + Identifier for the metafield (maximum of 30 characters). + """ + key: String! + ): Metafield + + """ + A paginated list of metafields associated with the resource. + """ + metafields( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MetafieldConnection! + + """ + List of prices and compare-at prices in the presentment currencies for this shop. + """ + presentmentPrices( + """ + The presentment currencies prices should return in. + """ + presentmentCurrencies: [CurrencyCode!] + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): ProductVariantPricePairConnection! + + """ + List of unit prices in the presentment currencies for this shop. + """ + presentmentUnitPrices( + """ + Specify the currencies in which to return presentment unit prices. + """ + presentmentCurrencies: [CurrencyCode!] + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MoneyV2Connection! + + """ + The product variant’s price. + """ + price: Money! @deprecated(reason: "Use `priceV2` instead") + + """ + The product variant’s price. + """ + priceV2: MoneyV2! + + """ + The product object that the product variant belongs to. + """ + product: Product! + + """ + The total sellable quantity of the variant for online sales channels. + """ + quantityAvailable: Int + + """ + Whether a customer needs to provide a shipping address when placing an order for the product variant. + """ + requiresShipping: Boolean! + + """ + List of product options applied to the variant. + """ + selectedOptions: [SelectedOption!]! + + """ + The SKU (stock keeping unit) associated with the variant. + """ + sku: String + + """ + The product variant’s title. + """ + title: String! + + """ + The unit price value for the variant based on the variant's measurement. + """ + unitPrice: MoneyV2 + + """ + The unit price measurement for the variant. + """ + unitPriceMeasurement: UnitPriceMeasurement + + """ + The weight of the product variant in the unit system specified with `weight_unit`. + """ + weight: Float + + """ + Unit of measurement for weight. + """ + weightUnit: WeightUnit! +} + +""" +An auto-generated type for paginating through multiple ProductVariants. +""" +type ProductVariantConnection { + """ + A list of edges. + """ + edges: [ProductVariantEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one ProductVariant and a cursor during pagination. +""" +type ProductVariantEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ProductVariantEdge. + """ + node: ProductVariant! +} + +""" +The compare-at price and price of a variant sharing a currency. +""" +type ProductVariantPricePair { + """ + The compare-at price of the variant with associated currency. + """ + compareAtPrice: MoneyV2 + + """ + The price of the variant with associated currency. + """ + price: MoneyV2! +} + +""" +An auto-generated type for paginating through multiple ProductVariantPricePairs. +""" +type ProductVariantPricePairConnection { + """ + A list of edges. + """ + edges: [ProductVariantPricePairEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one ProductVariantPricePair and a cursor during pagination. +""" +type ProductVariantPricePairEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ProductVariantPricePairEdge. + """ + node: ProductVariantPricePair! +} + +""" +The set of valid sort keys for the ProductVariant query. +""" +enum ProductVariantSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `sku` value. + """ + SKU + + """ + Sort by the `position` value. + """ + POSITION + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. +""" +type QueryRoot { + """ + List of the shop's articles. + """ + articles( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ArticleSortKeys = ID + + """ + Supported filter parameters: + - `author` + - `blog_title` + - `created_at` + - `tag` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ArticleConnection! + + """ + Find a blog by its handle. + """ + blogByHandle( + """ + The handle of the blog. + """ + handle: String! + ): Blog + + """ + List of the shop's blogs. + """ + blogs( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: BlogSortKeys = ID + + """ + Supported filter parameters: + - `created_at` + - `handle` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): BlogConnection! + + """ + Find a collection by its handle. + """ + collectionByHandle( + """ + The handle of the collection. + """ + handle: String! + ): Collection + + """ + List of the shop’s collections. + """ + collections( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: CollectionSortKeys = ID + + """ + Supported filter parameters: + - `collection_type` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): CollectionConnection! + + """ + Find a customer by its access token. + """ + customer( + """ + The customer access token. + """ + customerAccessToken: String! + ): Customer + node( + """ + The ID of the Node to return. + """ + id: ID! + ): Node + nodes( + """ + The IDs of the Nodes to return. + """ + ids: [ID!]! + ): [Node]! + + """ + Find a page by its handle. + """ + pageByHandle( + """ + The handle of the page. + """ + handle: String! + ): Page + + """ + List of the shop's pages. + """ + pages( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: PageSortKeys = ID + + """ + Supported filter parameters: + - `created_at` + - `handle` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): PageConnection! + + """ + Find a product by its handle. + """ + productByHandle( + """ + The handle of the product. + """ + handle: String! + ): Product + + """ + Find recommended products related to a given `product_id`. + To learn more about how recommendations are generated, see + [*Showing product recommendations on product pages*](https://help.shopify.com/themes/development/recommended-products). + """ + productRecommendations( + """ + The id of the product. + """ + productId: ID! + ): [Product!] + + """ + Tags added to products. + Additional access scope required: unauthenticated_read_product_tags. + """ + productTags( + """ + Returns up to the first `n` elements from the list. + """ + first: Int! + ): StringConnection! + + """ + List of product types for the shop's products that are published to your app. + """ + productTypes( + """ + Returns up to the first `n` elements from the list. + """ + first: Int! + ): StringConnection! + + """ + List of the shop’s products. + """ + products( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductSortKeys = ID + + """ + Supported filter parameters: + - `available_for_sale` + - `created_at` + - `product_type` + - `tag` + - `title` + - `updated_at` + - `variants.price` + - `vendor` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ProductConnection! + + """ + The list of public Storefront API versions, including supported, release candidate and unstable versions. + """ + publicApiVersions: [ApiVersion!]! + + """ + The shop associated with the storefront access token. + """ + shop: Shop! +} + +""" +SEO information. +""" +type SEO { + """ + The meta description. + """ + description: String + + """ + The SEO title. + """ + title: String +} + +""" +Script discount applications capture the intentions of a discount that +was created by a Shopify Script. +""" +type ScriptDiscountApplication implements DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + The description of the application as defined by the Script. + """ + description: String! @deprecated(reason: "Use `title` instead") + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The title of the application as defined by the Script. + """ + title: String! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +Properties used by customers to select a product variant. +Products can have multiple options, like different sizes or colors. +""" +type SelectedOption { + """ + The product option’s name. + """ + name: String! + + """ + The product option’s value. + """ + value: String! +} + +""" +Specifies the input fields required for a selected option. +""" +input SelectedOptionInput { + """ + The product option’s name. + """ + name: String! + + """ + The product option’s value. + """ + value: String! +} + +""" +A shipping rate to be applied to a checkout. +""" +type ShippingRate { + """ + Human-readable unique identifier for this shipping rate. + """ + handle: String! + + """ + Price of this shipping rate. + """ + price: Money! @deprecated(reason: "Use `priceV2` instead") + + """ + Price of this shipping rate. + """ + priceV2: MoneyV2! + + """ + Title of this shipping rate. + """ + title: String! +} + +""" +Shop represents a collection of the general settings and information about the shop. +""" +type Shop { + """ + List of the shop' articles. + """ + articles( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ArticleSortKeys = ID + + """ + Supported filter parameters: + - `author` + - `blog_title` + - `created_at` + - `tag` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ArticleConnection! @deprecated(reason: "Use `QueryRoot.articles` instead.") + + """ + List of the shop' blogs. + """ + blogs( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: BlogSortKeys = ID + + """ + Supported filter parameters: + - `created_at` + - `handle` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): BlogConnection! @deprecated(reason: "Use `QueryRoot.blogs` instead.") + + """ + Find a collection by its handle. + """ + collectionByHandle( + """ + The handle of the collection. + """ + handle: String! + ): Collection + @deprecated(reason: "Use `QueryRoot.collectionByHandle` instead.") + + """ + List of the shop’s collections. + """ + collections( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: CollectionSortKeys = ID + + """ + Supported filter parameters: + - `collection_type` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): CollectionConnection! + @deprecated(reason: "Use `QueryRoot.collections` instead.") + + """ + The three-letter code for the currency that the shop accepts. + """ + currencyCode: CurrencyCode! + @deprecated(reason: "Use `paymentSettings` instead") + + """ + A description of the shop. + """ + description: String + + """ + A string representing the way currency is formatted when the currency isn’t specified. + """ + moneyFormat: String! + + """ + The shop’s name. + """ + name: String! + + """ + Settings related to payments. + """ + paymentSettings: PaymentSettings! + + """ + The shop’s primary domain. + """ + primaryDomain: Domain! + + """ + The shop’s privacy policy. + """ + privacyPolicy: ShopPolicy + + """ + Find a product by its handle. + """ + productByHandle( + """ + The handle of the product. + """ + handle: String! + ): Product @deprecated(reason: "Use `QueryRoot.productByHandle` instead.") + + """ + A list of tags that have been added to products. + Additional access scope required: unauthenticated_read_product_tags. + """ + productTags( + """ + Returns up to the first `n` elements from the list. + """ + first: Int! + ): StringConnection! + @deprecated(reason: "Use `QueryRoot.productTags` instead.") + + """ + List of the shop’s product types. + """ + productTypes( + """ + Returns up to the first `n` elements from the list. + """ + first: Int! + ): StringConnection! + @deprecated(reason: "Use `QueryRoot.productTypes` instead.") + + """ + List of the shop’s products. + """ + products( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductSortKeys = ID + + """ + Supported filter parameters: + - `available_for_sale` + - `created_at` + - `product_type` + - `tag` + - `title` + - `updated_at` + - `variants.price` + - `vendor` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ProductConnection! @deprecated(reason: "Use `QueryRoot.products` instead.") + + """ + The shop’s refund policy. + """ + refundPolicy: ShopPolicy + + """ + The shop’s shipping policy. + """ + shippingPolicy: ShopPolicy + + """ + Countries that the shop ships to. + """ + shipsToCountries: [CountryCode!]! + + """ + The shop’s Shopify Payments account id. + """ + shopifyPaymentsAccountId: String + @deprecated(reason: "Use `paymentSettings` instead") + + """ + The shop’s terms of service. + """ + termsOfService: ShopPolicy +} + +""" +Policy that a merchant has configured for their store, such as their refund or privacy policy. +""" +type ShopPolicy implements Node { + """ + Policy text, maximum size of 64kb. + """ + body: String! + + """ + Policy’s handle. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + Policy’s title. + """ + title: String! + + """ + Public URL to the policy. + """ + url: URL! +} + +""" +An auto-generated type for paginating through multiple Strings. +""" +type StringConnection { + """ + A list of edges. + """ + edges: [StringEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one String and a cursor during pagination. +""" +type StringEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of StringEdge. + """ + node: String! +} + +""" +Specifies the fields required to complete a checkout with +a tokenized payment. +""" +input TokenizedPaymentInput { + """ + The amount of the payment. + """ + amount: Money! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + The type of payment token. + """ + type: String! + + """ + A simple string or JSON containing the required payment data for the tokenized payment. + """ + paymentData: String! + + """ + Executes the payment in test mode if possible. Defaults to `false`. + """ + test: Boolean + + """ + Public Hash Key used for AndroidPay payments only. + """ + identifier: String +} + +""" +Specifies the fields required to complete a checkout with +a tokenized payment. +""" +input TokenizedPaymentInputV2 { + """ + The amount and currency of the payment. + """ + paymentAmount: MoneyInput! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + A simple string or JSON containing the required payment data for the tokenized payment. + """ + paymentData: String! + + """ + Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`. + """ + test: Boolean + + """ + Public Hash Key used for AndroidPay payments only. + """ + identifier: String + + """ + The type of payment token. + """ + type: String! +} + +""" +Specifies the fields required to complete a checkout with +a tokenized payment. +""" +input TokenizedPaymentInputV3 { + """ + The amount and currency of the payment. + """ + paymentAmount: MoneyInput! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + A simple string or JSON containing the required payment data for the tokenized payment. + """ + paymentData: String! + + """ + Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`. + """ + test: Boolean + + """ + Public Hash Key used for AndroidPay payments only. + """ + identifier: String + + """ + The type of payment token. + """ + type: PaymentTokenType! +} + +""" +An object representing exchange of money for a product or service. +""" +type Transaction { + """ + The amount of money that the transaction was for. + """ + amount: Money! @deprecated(reason: "Use `amountV2` instead") + + """ + The amount of money that the transaction was for. + """ + amountV2: MoneyV2! + + """ + The kind of the transaction. + """ + kind: TransactionKind! + + """ + The status of the transaction. + """ + status: TransactionStatus! @deprecated(reason: "Use `statusV2` instead") + + """ + The status of the transaction. + """ + statusV2: TransactionStatus + + """ + Whether the transaction was done in test mode or not. + """ + test: Boolean! +} + +enum TransactionKind { + SALE + CAPTURE + AUTHORIZATION + EMV_AUTHORIZATION + CHANGE +} + +enum TransactionStatus { + PENDING + SUCCESS + FAILURE + ERROR +} + +""" +An RFC 3986 and RFC 3987 compliant URI string. + +Example value: `"https://johns-apparel.myshopify.com"`. +""" +scalar URL + +""" +The measurement used to calculate a unit price for a product variant (e.g. $9.99 / 100ml). +""" +type UnitPriceMeasurement { + """ + The type of unit of measurement for the unit price measurement. + """ + measuredType: UnitPriceMeasurementMeasuredType + + """ + The quantity unit for the unit price measurement. + """ + quantityUnit: UnitPriceMeasurementMeasuredUnit + + """ + The quantity value for the unit price measurement. + """ + quantityValue: Float! + + """ + The reference unit for the unit price measurement. + """ + referenceUnit: UnitPriceMeasurementMeasuredUnit + + """ + The reference value for the unit price measurement. + """ + referenceValue: Int! +} + +""" +The accepted types of unit of measurement. +""" +enum UnitPriceMeasurementMeasuredType { + """ + Unit of measurements representing volumes. + """ + VOLUME + + """ + Unit of measurements representing weights. + """ + WEIGHT + + """ + Unit of measurements representing lengths. + """ + LENGTH + + """ + Unit of measurements representing areas. + """ + AREA +} + +""" +The valid units of measurement for a unit price measurement. +""" +enum UnitPriceMeasurementMeasuredUnit { + """ + 1000 milliliters equals 1 liter. + """ + ML + + """ + 100 centiliters equals 1 liter. + """ + CL + + """ + Metric system unit of volume. + """ + L + + """ + 1 cubic meter equals 1000 liters. + """ + M3 + + """ + 1000 milligrams equals 1 gram. + """ + MG + + """ + Metric system unit of weight. + """ + G + + """ + 1 kilogram equals 1000 grams. + """ + KG + + """ + 1000 millimeters equals 1 meter. + """ + MM + + """ + 100 centimeters equals 1 meter. + """ + CM + + """ + Metric system unit of length. + """ + M + + """ + Metric system unit of area. + """ + M2 +} + +""" +Represents an error in the input of a mutation. +""" +type UserError implements DisplayableError { + """ + Path to the input field which caused the error. + """ + field: [String!] + + """ + The error message. + """ + message: String! +} + +""" +Represents a Shopify hosted video. +""" +type Video implements Node & Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image + + """ + The sources for a video. + """ + sources: [VideoSource!]! +} + +""" +Represents a source for a Shopify hosted video. +""" +type VideoSource { + """ + The format of the video source. + """ + format: String! + + """ + The height of the video. + """ + height: Int! + + """ + The video MIME type. + """ + mimeType: String! + + """ + The URL of the video. + """ + url: String! + + """ + The width of the video. + """ + width: Int! +} + +""" +Units of measurement for weight. +""" +enum WeightUnit { + """ + 1 kilogram equals 1000 grams. + """ + KILOGRAMS + + """ + Metric system unit of mass. + """ + GRAMS + + """ + 1 pound equals 16 ounces. + """ + POUNDS + + """ + Imperial system unit of mass. + """ + OUNCES +} diff --git a/framework/shopify/types.ts b/framework/shopify/types.ts new file mode 100644 index 00000000..e7bcb247 --- /dev/null +++ b/framework/shopify/types.ts @@ -0,0 +1,43 @@ +import * as Core from '@commerce/types' +import { CheckoutLineItem } from './schema' + +export type ShopifyCheckout = { + id: string + webUrl: string + lineItems: CheckoutLineItem[] +} + +export type Cart = Core.Cart & { + lineItems: LineItem[] +} +export interface LineItem extends Core.LineItem { + options?: any[] +} + +/** + * Cart mutations + */ + +export type OptionSelections = { + option_id: number + option_value: number | string +} + +export type CartItemBody = Core.CartItemBody & { + productId: string // The product id is always required for BC + optionSelections?: OptionSelections +} + +export type GetCartHandlerBody = Core.GetCartHandlerBody + +export type AddCartItemBody = Core.AddCartItemBody<CartItemBody> + +export type AddCartItemHandlerBody = Core.AddCartItemHandlerBody<CartItemBody> + +export type UpdateCartItemBody = Core.UpdateCartItemBody<CartItemBody> + +export type UpdateCartItemHandlerBody = Core.UpdateCartItemHandlerBody<CartItemBody> + +export type RemoveCartItemBody = Core.RemoveCartItemBody + +export type RemoveCartItemHandlerBody = Core.RemoveCartItemHandlerBody diff --git a/framework/shopify/utils/checkout-create.ts b/framework/shopify/utils/checkout-create.ts new file mode 100644 index 00000000..359d1631 --- /dev/null +++ b/framework/shopify/utils/checkout-create.ts @@ -0,0 +1,33 @@ +import Cookies from 'js-cookie' + +import { + SHOPIFY_CHECKOUT_ID_COOKIE, + SHOPIFY_CHECKOUT_URL_COOKIE, + SHOPIFY_COOKIE_EXPIRE, +} from '../const' + +import checkoutCreateMutation from './mutations/checkout-create' +import { CheckoutCreatePayload } from '../schema' + +export const checkoutCreate = async ( + fetch: any +): Promise<CheckoutCreatePayload> => { + const data = await fetch({ + query: checkoutCreateMutation, + }) + + const checkout = data.checkoutCreate?.checkout + const checkoutId = checkout?.id + + if (checkoutId) { + const options = { + expires: SHOPIFY_COOKIE_EXPIRE, + } + Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId, options) + Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout.webUrl, options) + } + + return checkout +} + +export default checkoutCreate diff --git a/framework/shopify/utils/checkout-to-cart.ts b/framework/shopify/utils/checkout-to-cart.ts new file mode 100644 index 00000000..034ff11d --- /dev/null +++ b/framework/shopify/utils/checkout-to-cart.ts @@ -0,0 +1,48 @@ +import { Cart } from '../types' +import { CommerceError } from '@commerce/utils/errors' + +import { + CheckoutLineItemsAddPayload, + CheckoutLineItemsRemovePayload, + CheckoutLineItemsUpdatePayload, + CheckoutCreatePayload, + CheckoutUserError, + Checkout, + Maybe, +} from '../schema' + +import { normalizeCart } from './normalize' +import throwUserErrors from './throw-user-errors' + +export type CheckoutQuery = { + checkout: Checkout + checkoutUserErrors?: Array<CheckoutUserError> +} + +export type CheckoutPayload = + | CheckoutLineItemsAddPayload + | CheckoutLineItemsUpdatePayload + | CheckoutLineItemsRemovePayload + | CheckoutCreatePayload + | CheckoutQuery + +const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => { + if (!checkoutPayload) { + throw new CommerceError({ + message: 'Missing checkout payload from response', + }) + } + + const checkout = checkoutPayload?.checkout + throwUserErrors(checkoutPayload?.checkoutUserErrors) + + if (!checkout) { + throw new CommerceError({ + message: 'Missing checkout object from response', + }) + } + + return normalizeCart(checkout) +} + +export default checkoutToCart diff --git a/framework/shopify/utils/customer-token.ts b/framework/shopify/utils/customer-token.ts new file mode 100644 index 00000000..85454cb8 --- /dev/null +++ b/framework/shopify/utils/customer-token.ts @@ -0,0 +1,21 @@ +import Cookies, { CookieAttributes } from 'js-cookie' +import { SHOPIFY_COOKIE_EXPIRE, SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '../const' + +export const getCustomerToken = () => Cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE) + +export const setCustomerToken = ( + token: string | null, + options?: CookieAttributes +) => { + if (!token) { + Cookies.remove(SHOPIFY_CUSTOMER_TOKEN_COOKIE) + } else { + Cookies.set( + SHOPIFY_CUSTOMER_TOKEN_COOKIE, + token, + options ?? { + expires: SHOPIFY_COOKIE_EXPIRE, + } + ) + } +} diff --git a/framework/shopify/utils/get-categories.ts b/framework/shopify/utils/get-categories.ts new file mode 100644 index 00000000..cce4b2ad --- /dev/null +++ b/framework/shopify/utils/get-categories.ts @@ -0,0 +1,29 @@ +import { ShopifyConfig } from '../api' +import { CollectionEdge } from '../schema' +import getSiteCollectionsQuery from './queries/get-all-collections-query' + +export type Category = { + entityId: string + name: string + path: string +} + +const getCategories = async (config: ShopifyConfig): Promise<Category[]> => { + const { data } = await config.fetch(getSiteCollectionsQuery, { + variables: { + first: 250, + }, + }) + + return ( + data.collections?.edges?.map( + ({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({ + entityId, + name, + path: `/${handle}`, + }) + ) ?? [] + ) +} + +export default getCategories diff --git a/framework/shopify/utils/get-checkout-id.ts b/framework/shopify/utils/get-checkout-id.ts new file mode 100644 index 00000000..11e3802d --- /dev/null +++ b/framework/shopify/utils/get-checkout-id.ts @@ -0,0 +1,8 @@ +import Cookies from 'js-cookie' +import { SHOPIFY_CHECKOUT_ID_COOKIE } from '../const' + +const getCheckoutId = (id?: string) => { + return id ?? Cookies.get(SHOPIFY_CHECKOUT_ID_COOKIE) +} + +export default getCheckoutId diff --git a/framework/shopify/utils/get-search-variables.ts b/framework/shopify/utils/get-search-variables.ts new file mode 100644 index 00000000..c1b40ae5 --- /dev/null +++ b/framework/shopify/utils/get-search-variables.ts @@ -0,0 +1,27 @@ +import getSortVariables from './get-sort-variables' +import type { SearchProductsInput } from '../product/use-search' + +export const getSearchVariables = ({ + brandId, + search, + categoryId, + sort, +}: SearchProductsInput) => { + let query = '' + + if (search) { + query += `product_type:${search} OR title:${search} OR tag:${search}` + } + + if (brandId) { + query += `${search ? ' AND ' : ''}vendor:${brandId}` + } + + return { + categoryId, + query, + ...getSortVariables(sort, !!categoryId), + } +} + +export default getSearchVariables diff --git a/framework/shopify/utils/get-sort-variables.ts b/framework/shopify/utils/get-sort-variables.ts new file mode 100644 index 00000000..141d9a18 --- /dev/null +++ b/framework/shopify/utils/get-sort-variables.ts @@ -0,0 +1,32 @@ +const getSortVariables = (sort?: string, isCategory: boolean = false) => { + let output = {} + switch (sort) { + case 'price-asc': + output = { + sortKey: 'PRICE', + reverse: false, + } + break + case 'price-desc': + output = { + sortKey: 'PRICE', + reverse: true, + } + break + case 'trending-desc': + output = { + sortKey: 'BEST_SELLING', + reverse: false, + } + break + case 'latest-desc': + output = { + sortKey: isCategory ? 'CREATED' : 'CREATED_AT', + reverse: true, + } + break + } + return output +} + +export default getSortVariables diff --git a/framework/shopify/utils/get-vendors.ts b/framework/shopify/utils/get-vendors.ts new file mode 100644 index 00000000..24843f17 --- /dev/null +++ b/framework/shopify/utils/get-vendors.ts @@ -0,0 +1,40 @@ +import { ShopifyConfig } from '../api' +import fetchAllProducts from '../api/utils/fetch-all-products' +import getAllProductVendors from './queries/get-all-product-vendors-query' + +export type Brand = { + entityId: string + name: string + path: string +} + +export type BrandEdge = { + node: Brand +} + +export type Brands = BrandEdge[] + +const getVendors = async (config: ShopifyConfig): Promise<BrandEdge[]> => { + const vendors = await fetchAllProducts({ + config, + query: getAllProductVendors, + variables: { + first: 250, + }, + }) + + let vendorsStrings = vendors.map(({ node: { vendor } }) => vendor) + + return [...new Set(vendorsStrings)].map((v) => { + const id = v.replace(/\s+/g, '-').toLowerCase() + return { + node: { + entityId: id, + name: v, + path: `brands/${id}`, + }, + } + }) +} + +export default getVendors diff --git a/framework/shopify/utils/handle-account-activation.ts b/framework/shopify/utils/handle-account-activation.ts new file mode 100644 index 00000000..d11f80ba --- /dev/null +++ b/framework/shopify/utils/handle-account-activation.ts @@ -0,0 +1,30 @@ +import { FetcherOptions } from '@commerce/utils/types' +import throwUserErrors from './throw-user-errors' + +import { + MutationCustomerActivateArgs, + MutationCustomerActivateByUrlArgs, +} from '../schema' +import { Mutation } from '../schema' +import { customerActivateByUrlMutation } from './mutations' + +const handleAccountActivation = async ( + fetch: <T = any, B = Body>(options: FetcherOptions<B>) => Promise<T>, + input: MutationCustomerActivateByUrlArgs +) => { + try { + const { customerActivateByUrl } = await fetch< + Mutation, + MutationCustomerActivateArgs + >({ + query: customerActivateByUrlMutation, + variables: { + input, + }, + }) + + throwUserErrors(customerActivateByUrl?.customerUserErrors) + } catch (error) {} +} + +export default handleAccountActivation diff --git a/framework/shopify/utils/handle-fetch-response.ts b/framework/shopify/utils/handle-fetch-response.ts new file mode 100644 index 00000000..8d7427d9 --- /dev/null +++ b/framework/shopify/utils/handle-fetch-response.ts @@ -0,0 +1,27 @@ +import { FetcherError } from '@commerce/utils/errors' + +export function getError(errors: any[], status: number) { + errors = errors ?? [{ message: 'Failed to fetch Shopify API' }] + return new FetcherError({ errors, status }) +} + +export async function getAsyncError(res: Response) { + const data = await res.json() + return getError(data.errors, res.status) +} + +const handleFetchResponse = async (res: Response) => { + if (res.ok) { + const { data, errors } = await res.json() + + if (errors && errors.length) { + throw getError(errors, res.status) + } + + return data + } + + throw await getAsyncError(res) +} + +export default handleFetchResponse diff --git a/framework/shopify/utils/handle-login.ts b/framework/shopify/utils/handle-login.ts new file mode 100644 index 00000000..de86fa1d --- /dev/null +++ b/framework/shopify/utils/handle-login.ts @@ -0,0 +1,36 @@ +import { FetcherOptions } from '@commerce/utils/types' +import { CustomerAccessTokenCreateInput } from '../schema' +import { setCustomerToken } from './customer-token' +import { customerAccessTokenCreateMutation } from './mutations' +import throwUserErrors from './throw-user-errors' + +const handleLogin = (data: any) => { + const response = data.customerAccessTokenCreate + throwUserErrors(response?.customerUserErrors) + + const customerAccessToken = response?.customerAccessToken + const accessToken = customerAccessToken?.accessToken + + if (accessToken) { + setCustomerToken(accessToken) + } + + return customerAccessToken +} + +export const handleAutomaticLogin = async ( + fetch: <T = any, B = Body>(options: FetcherOptions<B>) => Promise<T>, + input: CustomerAccessTokenCreateInput +) => { + try { + const loginData = await fetch({ + query: customerAccessTokenCreateMutation, + variables: { + input, + }, + }) + handleLogin(loginData) + } catch (error) {} +} + +export default handleLogin diff --git a/framework/shopify/utils/index.ts b/framework/shopify/utils/index.ts new file mode 100644 index 00000000..61e5975d --- /dev/null +++ b/framework/shopify/utils/index.ts @@ -0,0 +1,15 @@ +export { default as handleFetchResponse } from './handle-fetch-response' +export { default as getSearchVariables } from './get-search-variables' +export { default as getSortVariables } from './get-sort-variables' +export { default as getVendors } from './get-vendors' +export { default as getCategories } from './get-categories' +export { default as getCheckoutId } from './get-checkout-id' +export { default as checkoutCreate } from './checkout-create' +export { default as checkoutToCart } from './checkout-to-cart' +export { default as handleLogin, handleAutomaticLogin } from './handle-login' +export { default as handleAccountActivation } from './handle-account-activation' +export { default as throwUserErrors } from './throw-user-errors' +export * from './queries' +export * from './mutations' +export * from './normalize' +export * from './customer-token' diff --git a/framework/shopify/utils/mutations/associate-customer-with-checkout.ts b/framework/shopify/utils/mutations/associate-customer-with-checkout.ts new file mode 100644 index 00000000..6b1350e0 --- /dev/null +++ b/framework/shopify/utils/mutations/associate-customer-with-checkout.ts @@ -0,0 +1,18 @@ +const associateCustomerWithCheckoutMutation = /* GraphQl */ ` +mutation associateCustomerWithCheckout($checkoutId: ID!, $customerAccessToken: String!) { + checkoutCustomerAssociateV2(checkoutId: $checkoutId, customerAccessToken: $customerAccessToken) { + checkout { + id + } + checkoutUserErrors { + code + field + message + } + customer { + id + } + } + } +` +export default associateCustomerWithCheckoutMutation diff --git a/framework/shopify/utils/mutations/checkout-create.ts b/framework/shopify/utils/mutations/checkout-create.ts new file mode 100644 index 00000000..ffbd555c --- /dev/null +++ b/framework/shopify/utils/mutations/checkout-create.ts @@ -0,0 +1,17 @@ +import { checkoutDetailsFragment } from '../queries/get-checkout-query' + +const checkoutCreateMutation = /* GraphQL */ ` + mutation { + checkoutCreate(input: {}) { + checkoutUserErrors { + code + field + message + } + checkout { + ${checkoutDetailsFragment} + } + } + } +` +export default checkoutCreateMutation diff --git a/framework/shopify/utils/mutations/checkout-line-item-add.ts b/framework/shopify/utils/mutations/checkout-line-item-add.ts new file mode 100644 index 00000000..2282c4e2 --- /dev/null +++ b/framework/shopify/utils/mutations/checkout-line-item-add.ts @@ -0,0 +1,17 @@ +import { checkoutDetailsFragment } from '../queries/get-checkout-query' + +const checkoutLineItemAddMutation = /* GraphQL */ ` + mutation($checkoutId: ID!, $lineItems: [CheckoutLineItemInput!]!) { + checkoutLineItemsAdd(checkoutId: $checkoutId, lineItems: $lineItems) { + checkoutUserErrors { + code + field + message + } + checkout { + ${checkoutDetailsFragment} + } + } + } +` +export default checkoutLineItemAddMutation diff --git a/framework/shopify/utils/mutations/checkout-line-item-remove.ts b/framework/shopify/utils/mutations/checkout-line-item-remove.ts new file mode 100644 index 00000000..8dea4ce0 --- /dev/null +++ b/framework/shopify/utils/mutations/checkout-line-item-remove.ts @@ -0,0 +1,20 @@ +import { checkoutDetailsFragment } from '../queries/get-checkout-query' + +const checkoutLineItemRemoveMutation = /* GraphQL */ ` + mutation($checkoutId: ID!, $lineItemIds: [ID!]!) { + checkoutLineItemsRemove( + checkoutId: $checkoutId + lineItemIds: $lineItemIds + ) { + checkoutUserErrors { + code + field + message + } + checkout { + ${checkoutDetailsFragment} + } + } + } +` +export default checkoutLineItemRemoveMutation diff --git a/framework/shopify/utils/mutations/checkout-line-item-update.ts b/framework/shopify/utils/mutations/checkout-line-item-update.ts new file mode 100644 index 00000000..76254341 --- /dev/null +++ b/framework/shopify/utils/mutations/checkout-line-item-update.ts @@ -0,0 +1,17 @@ +import { checkoutDetailsFragment } from '../queries/get-checkout-query' + +const checkoutLineItemUpdateMutation = /* GraphQL */ ` + mutation($checkoutId: ID!, $lineItems: [CheckoutLineItemUpdateInput!]!) { + checkoutLineItemsUpdate(checkoutId: $checkoutId, lineItems: $lineItems) { + checkoutUserErrors { + code + field + message + } + checkout { + ${checkoutDetailsFragment} + } + } + } +` +export default checkoutLineItemUpdateMutation diff --git a/framework/shopify/utils/mutations/customer-access-token-create.ts b/framework/shopify/utils/mutations/customer-access-token-create.ts new file mode 100644 index 00000000..7a45c3f4 --- /dev/null +++ b/framework/shopify/utils/mutations/customer-access-token-create.ts @@ -0,0 +1,16 @@ +const customerAccessTokenCreateMutation = /* GraphQL */ ` + mutation customerAccessTokenCreate($input: CustomerAccessTokenCreateInput!) { + customerAccessTokenCreate(input: $input) { + customerAccessToken { + accessToken + expiresAt + } + customerUserErrors { + code + field + message + } + } + } +` +export default customerAccessTokenCreateMutation diff --git a/framework/shopify/utils/mutations/customer-access-token-delete.ts b/framework/shopify/utils/mutations/customer-access-token-delete.ts new file mode 100644 index 00000000..c46eff1e --- /dev/null +++ b/framework/shopify/utils/mutations/customer-access-token-delete.ts @@ -0,0 +1,14 @@ +const customerAccessTokenDeleteMutation = /* GraphQL */ ` + mutation customerAccessTokenDelete($customerAccessToken: String!) { + customerAccessTokenDelete(customerAccessToken: $customerAccessToken) { + deletedAccessToken + deletedCustomerAccessTokenId + userErrors { + field + message + } + } + } +` + +export default customerAccessTokenDeleteMutation diff --git a/framework/shopify/utils/mutations/customer-activate-by-url.ts b/framework/shopify/utils/mutations/customer-activate-by-url.ts new file mode 100644 index 00000000..345d502b --- /dev/null +++ b/framework/shopify/utils/mutations/customer-activate-by-url.ts @@ -0,0 +1,19 @@ +const customerActivateByUrlMutation = /* GraphQL */ ` + mutation customerActivateByUrl($activationUrl: URL!, $password: String!) { + customerActivateByUrl(activationUrl: $activationUrl, password: $password) { + customer { + id + } + customerAccessToken { + accessToken + expiresAt + } + customerUserErrors { + code + field + message + } + } + } +` +export default customerActivateByUrlMutation diff --git a/framework/shopify/utils/mutations/customer-activate.ts b/framework/shopify/utils/mutations/customer-activate.ts new file mode 100644 index 00000000..b1d057c6 --- /dev/null +++ b/framework/shopify/utils/mutations/customer-activate.ts @@ -0,0 +1,19 @@ +const customerActivateMutation = /* GraphQL */ ` + mutation customerActivate($id: ID!, $input: CustomerActivateInput!) { + customerActivate(id: $id, input: $input) { + customer { + id + } + customerAccessToken { + accessToken + expiresAt + } + customerUserErrors { + code + field + message + } + } + } +` +export default customerActivateMutation diff --git a/framework/shopify/utils/mutations/customer-create.ts b/framework/shopify/utils/mutations/customer-create.ts new file mode 100644 index 00000000..05c728a2 --- /dev/null +++ b/framework/shopify/utils/mutations/customer-create.ts @@ -0,0 +1,15 @@ +const customerCreateMutation = /* GraphQL */ ` + mutation customerCreate($input: CustomerCreateInput!) { + customerCreate(input: $input) { + customerUserErrors { + code + field + message + } + customer { + id + } + } + } +` +export default customerCreateMutation diff --git a/framework/shopify/utils/mutations/index.ts b/framework/shopify/utils/mutations/index.ts new file mode 100644 index 00000000..165fb192 --- /dev/null +++ b/framework/shopify/utils/mutations/index.ts @@ -0,0 +1,9 @@ +export { default as customerCreateMutation } from './customer-create' +export { default as checkoutCreateMutation } from './checkout-create' +export { default as checkoutLineItemAddMutation } from './checkout-line-item-add' +export { default as checkoutLineItemUpdateMutation } from './checkout-line-item-update' +export { default as checkoutLineItemRemoveMutation } from './checkout-line-item-remove' +export { default as customerAccessTokenCreateMutation } from './customer-access-token-create' +export { default as customerAccessTokenDeleteMutation } from './customer-access-token-delete' +export { default as customerActivateMutation } from './customer-activate' +export { default as customerActivateByUrlMutation } from './customer-activate-by-url' diff --git a/framework/shopify/utils/normalize.ts b/framework/shopify/utils/normalize.ts new file mode 100644 index 00000000..4ebc3a1a --- /dev/null +++ b/framework/shopify/utils/normalize.ts @@ -0,0 +1,165 @@ +import { Product } from '@commerce/types' + +import { + Product as ShopifyProduct, + Checkout, + CheckoutLineItemEdge, + SelectedOption, + ImageConnection, + ProductVariantConnection, + MoneyV2, + ProductOption, +} from '../schema' + +import type { Cart, LineItem } from '../types' + +const money = ({ amount, currencyCode }: MoneyV2) => { + return { + value: +amount, + currencyCode, + } +} + +const normalizeProductOption = ({ + id, + name: displayName, + values, +}: ProductOption) => { + return { + __typename: 'MultipleChoiceOption', + id, + displayName, + values: values.map((value) => { + let output: any = { + label: value, + } + if (displayName.match(/colou?r/gi)) { + output = { + ...output, + hexColors: [value], + } + } + return output + }), + } +} + +const normalizeProductImages = ({ edges }: ImageConnection) => + edges?.map(({ node: { originalSrc: url, ...rest } }) => ({ + url, + ...rest, + })) + +const normalizeProductVariants = ({ edges }: ProductVariantConnection) => { + return edges?.map( + ({ + node: { id, selectedOptions, sku, title, priceV2, compareAtPriceV2 }, + }) => { + return { + id, + name: title, + sku: sku ?? id, + price: +priceV2.amount, + listPrice: +compareAtPriceV2?.amount, + requiresShipping: true, + options: selectedOptions.map(({ name, value }: SelectedOption) => { + const options = normalizeProductOption({ + id, + name, + values: [value], + }) + return options + }), + } + } + ) +} + +export function normalizeProduct(productNode: ShopifyProduct): Product { + const { + id, + title: name, + vendor, + images, + variants, + description, + descriptionHtml, + handle, + priceRange, + options, + ...rest + } = productNode + + const product = { + id, + name, + vendor, + path: `/${handle}`, + slug: handle?.replace(/^\/+|\/+$/g, ''), + price: money(priceRange?.minVariantPrice), + images: normalizeProductImages(images), + variants: variants ? normalizeProductVariants(variants) : [], + options: options + ? options + .filter((o) => o.name !== 'Title') // By default Shopify adds a 'Title' name when there's only one option. We don't need it. https://community.shopify.com/c/Shopify-APIs-SDKs/Adding-new-product-variant-is-automatically-adding-quot-Default/td-p/358095 + .map((o) => normalizeProductOption(o)) + : [], + ...(description && { description }), + ...(descriptionHtml && { descriptionHtml }), + ...rest, + } + + return product +} + +export function normalizeCart(checkout: Checkout): Cart { + return { + id: checkout.id, + customerId: '', + email: '', + createdAt: checkout.createdAt, + currency: { + code: checkout.totalPriceV2?.currencyCode, + }, + taxesIncluded: checkout.taxesIncluded, + lineItems: checkout.lineItems?.edges.map(normalizeLineItem), + lineItemsSubtotalPrice: +checkout.subtotalPriceV2?.amount, + subtotalPrice: +checkout.subtotalPriceV2?.amount, + totalPrice: checkout.totalPriceV2?.amount, + discounts: [], + } +} + +function normalizeLineItem({ + node: { id, title, variant, quantity, ...rest }, +}: CheckoutLineItemEdge): LineItem { + return { + id, + variantId: String(variant?.id), + productId: String(variant?.id), + name: `${title}`, + quantity, + variant: { + id: String(variant?.id), + sku: variant?.sku ?? '', + name: variant?.title!, + image: { + url: variant?.image?.originalSrc ?? '/product-img-placeholder.svg', + }, + requiresShipping: variant?.requiresShipping ?? false, + price: variant?.priceV2?.amount, + listPrice: variant?.compareAtPriceV2?.amount, + }, + path: String(variant?.product?.handle), + discounts: [], + options: + // By default Shopify adds a default variant with default names, we're removing it. https://community.shopify.com/c/Shopify-APIs-SDKs/Adding-new-product-variant-is-automatically-adding-quot-Default/td-p/358095 + variant?.title == 'Default Title' + ? [] + : [ + { + value: variant?.title, + }, + ], + } +} diff --git a/framework/shopify/utils/queries/get-all-collections-query.ts b/framework/shopify/utils/queries/get-all-collections-query.ts new file mode 100644 index 00000000..2abf374d --- /dev/null +++ b/framework/shopify/utils/queries/get-all-collections-query.ts @@ -0,0 +1,14 @@ +const getSiteCollectionsQuery = /* GraphQL */ ` + query getSiteCollections($first: Int!) { + collections(first: $first) { + edges { + node { + id + title + handle + } + } + } + } +` +export default getSiteCollectionsQuery diff --git a/framework/shopify/utils/queries/get-all-pages-query.ts b/framework/shopify/utils/queries/get-all-pages-query.ts new file mode 100644 index 00000000..e3aee1f1 --- /dev/null +++ b/framework/shopify/utils/queries/get-all-pages-query.ts @@ -0,0 +1,14 @@ +export const getAllPagesQuery = /* GraphQL */ ` + query getAllPages($first: Int = 250) { + pages(first: $first) { + edges { + node { + id + title + handle + } + } + } + } +` +export default getAllPagesQuery diff --git a/framework/shopify/utils/queries/get-all-product-vendors-query.ts b/framework/shopify/utils/queries/get-all-product-vendors-query.ts new file mode 100644 index 00000000..be08b8ec --- /dev/null +++ b/framework/shopify/utils/queries/get-all-product-vendors-query.ts @@ -0,0 +1,17 @@ +const getAllProductVendors = /* GraphQL */ ` + query getAllProductVendors($first: Int = 250, $cursor: String) { + products(first: $first, after: $cursor) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + vendor + } + cursor + } + } + } +` +export default getAllProductVendors diff --git a/framework/shopify/utils/queries/get-all-products-paths-query.ts b/framework/shopify/utils/queries/get-all-products-paths-query.ts new file mode 100644 index 00000000..56298c20 --- /dev/null +++ b/framework/shopify/utils/queries/get-all-products-paths-query.ts @@ -0,0 +1,17 @@ +const getAllProductsPathsQuery = /* GraphQL */ ` + query getAllProductPaths($first: Int = 250, $cursor: String) { + products(first: $first, after: $cursor) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + handle + } + cursor + } + } + } +` +export default getAllProductsPathsQuery diff --git a/framework/shopify/utils/queries/get-all-products-query.ts b/framework/shopify/utils/queries/get-all-products-query.ts new file mode 100644 index 00000000..f48140d3 --- /dev/null +++ b/framework/shopify/utils/queries/get-all-products-query.ts @@ -0,0 +1,56 @@ +export const productConnection = ` +pageInfo { + hasNextPage + hasPreviousPage +} +edges { + node { + id + title + vendor + handle + priceRange { + minVariantPrice { + amount + currencyCode + } + } + images(first: 1) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + originalSrc + altText + width + height + } + } + } + } +}` + +export const productsFragment = ` +products( + first: $first + sortKey: $sortKey + reverse: $reverse + query: $query +) { + ${productConnection} +} +` + +const getAllProductsQuery = /* GraphQL */ ` + query getAllProducts( + $first: Int = 250 + $query: String = "" + $sortKey: ProductSortKeys = RELEVANCE + $reverse: Boolean = false + ) { + ${productsFragment} + } +` +export default getAllProductsQuery diff --git a/framework/shopify/utils/queries/get-checkout-query.ts b/framework/shopify/utils/queries/get-checkout-query.ts new file mode 100644 index 00000000..d8758e32 --- /dev/null +++ b/framework/shopify/utils/queries/get-checkout-query.ts @@ -0,0 +1,65 @@ +export const checkoutDetailsFragment = ` + id + webUrl + subtotalPriceV2{ + amount + currencyCode + } + totalTaxV2 { + amount + currencyCode + } + totalPriceV2 { + amount + currencyCode + } + completedAt + createdAt + taxesIncluded + lineItems(first: 250) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + id + title + variant { + id + sku + title + image { + originalSrc + altText + width + height + } + priceV2{ + amount + currencyCode + } + compareAtPriceV2{ + amount + currencyCode + } + product { + handle + } + } + quantity + } + } + } +` + +const getCheckoutQuery = /* GraphQL */ ` + query($checkoutId: ID!) { + node(id: $checkoutId) { + ... on Checkout { + ${checkoutDetailsFragment} + } + } + } +` +export default getCheckoutQuery diff --git a/framework/shopify/utils/queries/get-collection-products-query.ts b/framework/shopify/utils/queries/get-collection-products-query.ts new file mode 100644 index 00000000..04766caa --- /dev/null +++ b/framework/shopify/utils/queries/get-collection-products-query.ts @@ -0,0 +1,24 @@ +import { productConnection } from './get-all-products-query' + +const getCollectionProductsQuery = /* GraphQL */ ` + query getProductsFromCollection( + $categoryId: ID! + $first: Int = 250 + $sortKey: ProductCollectionSortKeys = RELEVANCE + $reverse: Boolean = false + ) { + node(id: $categoryId) { + id + ... on Collection { + products( + first: $first + sortKey: $sortKey + reverse: $reverse + ) { + ${productConnection} + } + } + } + } +` +export default getCollectionProductsQuery diff --git a/framework/shopify/utils/queries/get-customer-id-query.ts b/framework/shopify/utils/queries/get-customer-id-query.ts new file mode 100644 index 00000000..076ceb10 --- /dev/null +++ b/framework/shopify/utils/queries/get-customer-id-query.ts @@ -0,0 +1,8 @@ +export const getCustomerQuery = /* GraphQL */ ` + query getCustomerId($customerAccessToken: String!) { + customer(customerAccessToken: $customerAccessToken) { + id + } + } +` +export default getCustomerQuery diff --git a/framework/shopify/utils/queries/get-customer-query.ts b/framework/shopify/utils/queries/get-customer-query.ts new file mode 100644 index 00000000..87e37e68 --- /dev/null +++ b/framework/shopify/utils/queries/get-customer-query.ts @@ -0,0 +1,16 @@ +export const getCustomerQuery = /* GraphQL */ ` + query getCustomer($customerAccessToken: String!) { + customer(customerAccessToken: $customerAccessToken) { + id + firstName + lastName + displayName + email + phone + tags + acceptsMarketing + createdAt + } + } +` +export default getCustomerQuery diff --git a/framework/shopify/utils/queries/get-page-query.ts b/framework/shopify/utils/queries/get-page-query.ts new file mode 100644 index 00000000..2ca79abd --- /dev/null +++ b/framework/shopify/utils/queries/get-page-query.ts @@ -0,0 +1,14 @@ +export const getPageQuery = /* GraphQL */ ` + query($id: ID!) { + node(id: $id) { + id + ... on Page { + title + handle + body + bodySummary + } + } + } +` +export default getPageQuery diff --git a/framework/shopify/utils/queries/get-product-query.ts b/framework/shopify/utils/queries/get-product-query.ts new file mode 100644 index 00000000..5c109901 --- /dev/null +++ b/framework/shopify/utils/queries/get-product-query.ts @@ -0,0 +1,69 @@ +const getProductQuery = /* GraphQL */ ` + query getProductBySlug($slug: String!) { + productByHandle(handle: $slug) { + id + handle + title + productType + vendor + description + descriptionHtml + options { + id + name + values + } + priceRange { + maxVariantPrice { + amount + currencyCode + } + minVariantPrice { + amount + currencyCode + } + } + variants(first: 250) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + id + title + sku + selectedOptions { + name + value + } + priceV2 { + amount + currencyCode + } + compareAtPriceV2 { + amount + currencyCode + } + } + } + } + images(first: 250) { + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + originalSrc + altText + width + height + } + } + } + } + } +` + +export default getProductQuery diff --git a/framework/shopify/utils/queries/index.ts b/framework/shopify/utils/queries/index.ts new file mode 100644 index 00000000..e19be9c8 --- /dev/null +++ b/framework/shopify/utils/queries/index.ts @@ -0,0 +1,10 @@ +export { default as getSiteCollectionsQuery } from './get-all-collections-query' +export { default as getProductQuery } from './get-product-query' +export { default as getAllProductsQuery } from './get-all-products-query' +export { default as getAllProductsPathtsQuery } from './get-all-products-paths-query' +export { default as getAllProductVendors } from './get-all-product-vendors-query' +export { default as getCollectionProductsQuery } from './get-collection-products-query' +export { default as getCheckoutQuery } from './get-checkout-query' +export { default as getAllPagesQuery } from './get-all-pages-query' +export { default as getPageQuery } from './get-page-query' +export { default as getCustomerQuery } from './get-customer-query' diff --git a/framework/shopify/utils/throw-user-errors.ts b/framework/shopify/utils/throw-user-errors.ts new file mode 100644 index 00000000..5488ba28 --- /dev/null +++ b/framework/shopify/utils/throw-user-errors.ts @@ -0,0 +1,38 @@ +import { ValidationError } from '@commerce/utils/errors' + +import { + CheckoutErrorCode, + CheckoutUserError, + CustomerErrorCode, + CustomerUserError, +} from '../schema' + +export type UserErrors = Array<CheckoutUserError | CustomerUserError> + +export type UserErrorCode = + | CustomerErrorCode + | CheckoutErrorCode + | null + | undefined + +const getCustomMessage = (code: UserErrorCode, message: string) => { + switch (code) { + case 'UNIDENTIFIED_CUSTOMER': + message = 'Cannot find an account that matches the provided credentials' + break + } + return message +} + +export const throwUserErrors = (errors?: UserErrors) => { + if (errors && errors.length) { + throw new ValidationError({ + errors: errors.map(({ code, message }) => ({ + code: code ?? 'validation_error', + message: getCustomMessage(code, message), + })), + }) + } +} + +export default throwUserErrors diff --git a/framework/shopify/wishlist/use-add-item.tsx b/framework/shopify/wishlist/use-add-item.tsx new file mode 100644 index 00000000..75f067c3 --- /dev/null +++ b/framework/shopify/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/framework/shopify/wishlist/use-remove-item.tsx b/framework/shopify/wishlist/use-remove-item.tsx new file mode 100644 index 00000000..a2d3a8a0 --- /dev/null +++ b/framework/shopify/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/framework/shopify/wishlist/use-wishlist.tsx b/framework/shopify/wishlist/use-wishlist.tsx new file mode 100644 index 00000000..d2ce9db5 --- /dev/null +++ b/framework/shopify/wishlist/use-wishlist.tsx @@ -0,0 +1,46 @@ +// TODO: replace this hook and other wishlist hooks with a handler, or remove them if +// Shopify doesn't have a wishlist + +import { HookFetcher } from '@commerce/utils/types' +import { Product } from '../schema' + +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<Wishlist | null, UseWishlistInput> = () => { + return null +} + +export function extendHook( + customFetcher: typeof fetcher, + // swrOptions?: SwrOptions<Wishlist | null, UseWishlistInput> + swrOptions?: any +) { + const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => { + return { data: null } + } + + useWishlist.extend = extendHook + + return useWishlist +} + +export default extendHook(fetcher) diff --git a/framework/swell/.env.template b/framework/swell/.env.template new file mode 100644 index 00000000..43c931f4 --- /dev/null +++ b/framework/swell/.env.template @@ -0,0 +1,5 @@ +SWELL_STORE_DOMAIN= +SWELL_STOREFRONT_ACCESS_TOKEN= + +NEXT_PUBLIC_SWELL_STORE_ID= +NEXT_PUBLIC_SWELL_PUBLIC_KEY= diff --git a/framework/swell/api/cart/index.ts b/framework/swell/api/cart/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/swell/api/cart/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/swell/api/catalog/index.ts b/framework/swell/api/catalog/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/swell/api/catalog/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/swell/api/catalog/products.ts b/framework/swell/api/catalog/products.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/swell/api/catalog/products.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/swell/api/checkout/index.ts b/framework/swell/api/checkout/index.ts new file mode 100644 index 00000000..0759e2ab --- /dev/null +++ b/framework/swell/api/checkout/index.ts @@ -0,0 +1,20 @@ +import createApiHandler, { SwellApiHandler } from '../utils/create-api-handler' + +import { SWELL_CHECKOUT_URL_COOKIE } from '../../const' + +import { getConfig } from '..' + +const checkoutApi: SwellApiHandler<any> = async (req, res, config) => { + config = getConfig() + + const { cookies } = req + const checkoutUrl = cookies[SWELL_CHECKOUT_URL_COOKIE] + + if (checkoutUrl) { + res.redirect(checkoutUrl) + } else { + res.redirect('/cart') + } +} + +export default createApiHandler(checkoutApi, {}, {}) diff --git a/framework/swell/api/customer.ts b/framework/swell/api/customer.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/swell/api/customer.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/swell/api/customers/index.ts b/framework/swell/api/customers/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/swell/api/customers/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/swell/api/customers/login.ts b/framework/swell/api/customers/login.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/swell/api/customers/login.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/swell/api/customers/logout.ts b/framework/swell/api/customers/logout.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/swell/api/customers/logout.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/swell/api/customers/signup.ts b/framework/swell/api/customers/signup.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/swell/api/customers/signup.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/swell/api/index.ts b/framework/swell/api/index.ts new file mode 100644 index 00000000..1494af9c --- /dev/null +++ b/framework/swell/api/index.ts @@ -0,0 +1,50 @@ +import type { CommerceAPIConfig } from '@commerce/api' + +import { + SWELL_CHECKOUT_ID_COOKIE, + SWELL_CUSTOMER_TOKEN_COOKIE, + SWELL_COOKIE_EXPIRE, +} from '../const' + +import fetchApi from './utils/fetch-swell-api' + +export interface SwellConfig extends CommerceAPIConfig { + fetch: any +} + +export class Config { + private config: SwellConfig + + constructor(config: SwellConfig) { + this.config = config + } + + getConfig(userConfig: Partial<SwellConfig> = {}) { + return Object.entries(userConfig).reduce<SwellConfig>( + (cfg, [key, value]) => Object.assign(cfg, { [key]: value }), + { ...this.config } + ) + } + + setConfig(newConfig: Partial<SwellConfig>) { + Object.assign(this.config, newConfig) + } +} + +const config = new Config({ + locale: 'en-US', + commerceUrl: '', + apiToken: ''!, + cartCookie: SWELL_CHECKOUT_ID_COOKIE, + cartCookieMaxAge: SWELL_COOKIE_EXPIRE, + fetch: fetchApi, + customerCookie: SWELL_CUSTOMER_TOKEN_COOKIE, +}) + +export function getConfig(userConfig?: Partial<SwellConfig>) { + return config.getConfig(userConfig) +} + +export function setConfig(newConfig: Partial<SwellConfig>) { + return config.setConfig(newConfig) +} diff --git a/framework/swell/api/operations/get-page.ts b/framework/swell/api/operations/get-page.ts new file mode 100644 index 00000000..b04002dd --- /dev/null +++ b/framework/swell/api/operations/get-page.ts @@ -0,0 +1,25 @@ +import { Page } from '../../schema' +import { SwellConfig, getConfig } from '..' + +export type GetPageResult<T extends { page?: any } = { page?: Page }> = T + +export type PageVariables = { + id: string +} + +async function getPage({ + url, + variables, + config, + preview, +}: { + url?: string + variables: PageVariables + config?: SwellConfig + preview?: boolean +}): Promise<GetPageResult> { + config = getConfig(config) + return {} +} + +export default getPage diff --git a/framework/swell/api/utils/create-api-handler.ts b/framework/swell/api/utils/create-api-handler.ts new file mode 100644 index 00000000..bd40a7ee --- /dev/null +++ b/framework/swell/api/utils/create-api-handler.ts @@ -0,0 +1,58 @@ +import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next' +import { SwellConfig, getConfig } from '..' + +export type SwellApiHandler< + T = any, + H extends SwellHandlers = {}, + Options extends {} = {} +> = ( + req: NextApiRequest, + res: NextApiResponse<SwellApiResponse<T>>, + config: SwellConfig, + handlers: H, + // Custom configs that may be used by a particular handler + options: Options +) => void | Promise<void> + +export type SwellHandler<T = any, Body = null> = (options: { + req: NextApiRequest + res: NextApiResponse<SwellApiResponse<T>> + config: SwellConfig + body: Body +}) => void | Promise<void> + +export type SwellHandlers<T = any> = { + [k: string]: SwellHandler<T, any> +} + +export type SwellApiResponse<T> = { + data: T | null + errors?: { message: string; code?: string }[] +} + +export default function createApiHandler< + T = any, + H extends SwellHandlers = {}, + Options extends {} = {} +>( + handler: SwellApiHandler<T, H, Options>, + handlers: H, + defaultOptions: Options +) { + return function getApiHandler({ + config, + operations, + options, + }: { + config?: SwellConfig + operations?: Partial<H> + options?: Options extends {} ? Partial<Options> : never + } = {}): NextApiHandler { + const ops = { ...operations, ...handlers } + const opts = { ...defaultOptions, ...options } + + return function apiHandler(req, res) { + return handler(req, res, getConfig(config), ops, opts) + } + } +} diff --git a/framework/swell/api/utils/fetch-swell-api.ts b/framework/swell/api/utils/fetch-swell-api.ts new file mode 100644 index 00000000..65caed76 --- /dev/null +++ b/framework/swell/api/utils/fetch-swell-api.ts @@ -0,0 +1,7 @@ +import { swellConfig } from '../..' + +const fetchApi = async (query: string, method: string, variables: [] = []) => { + const { swell } = swellConfig + return swell[query][method](...variables) +} +export default fetchApi diff --git a/framework/swell/api/utils/fetch.ts b/framework/swell/api/utils/fetch.ts new file mode 100644 index 00000000..0b836710 --- /dev/null +++ b/framework/swell/api/utils/fetch.ts @@ -0,0 +1,2 @@ +import zeitFetch from '@vercel/fetch' +export default zeitFetch() diff --git a/framework/swell/api/utils/is-allowed-method.ts b/framework/swell/api/utils/is-allowed-method.ts new file mode 100644 index 00000000..78bbba56 --- /dev/null +++ b/framework/swell/api/utils/is-allowed-method.ts @@ -0,0 +1,28 @@ +import type { NextApiRequest, NextApiResponse } from 'next' + +export default function isAllowedMethod( + req: NextApiRequest, + res: NextApiResponse, + allowedMethods: string[] +) { + const methods = allowedMethods.includes('OPTIONS') + ? allowedMethods + : [...allowedMethods, 'OPTIONS'] + + if (!req.method || !methods.includes(req.method)) { + res.status(405) + res.setHeader('Allow', methods.join(', ')) + res.end() + return false + } + + if (req.method === 'OPTIONS') { + res.status(200) + res.setHeader('Allow', methods.join(', ')) + res.setHeader('Content-Length', '0') + res.end() + return false + } + + return true +} diff --git a/framework/swell/api/wishlist/index.tsx b/framework/swell/api/wishlist/index.tsx new file mode 100644 index 00000000..a7285667 --- /dev/null +++ b/framework/swell/api/wishlist/index.tsx @@ -0,0 +1,2 @@ +export type WishlistItem = { product: any; id: number } +export default function () {} diff --git a/framework/swell/auth/use-login.tsx b/framework/swell/auth/use-login.tsx new file mode 100644 index 00000000..d0faa929 --- /dev/null +++ b/framework/swell/auth/use-login.tsx @@ -0,0 +1,76 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError, ValidationError } from '@commerce/utils/errors' +import useCustomer from '../customer/use-customer' +import { + CustomerAccessTokenCreateInput, + CustomerUserError, + Mutation, + MutationCheckoutCreateArgs, +} from '../schema' +import useLogin, { UseLogin } from '@commerce/auth/use-login' +import { setCustomerToken } from '../utils' + +export default useLogin as UseLogin<typeof handler> + +const getErrorMessage = ({ code, message }: CustomerUserError) => { + switch (code) { + case 'UNIDENTIFIED_CUSTOMER': + message = 'Cannot find an account that matches the provided credentials' + break + } + return message +} + +export const handler: MutationHook<null, {}, CustomerAccessTokenCreateInput> = { + fetchOptions: { + query: 'account', + method: 'login', + }, + async fetcher({ input: { email, password }, options, fetch }) { + if (!(email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to login', + }) + } + + const { customerAccessTokenCreate } = await fetch< + Mutation, + MutationCheckoutCreateArgs + >({ + ...options, + variables: [email, password], + }) + + const errors = customerAccessTokenCreate?.customerUserErrors + + if (errors && errors.length) { + throw new ValidationError({ + message: getErrorMessage(errors[0]), + }) + } + const customerAccessToken = customerAccessTokenCreate?.customerAccessToken + const accessToken = customerAccessToken?.accessToken + + if (accessToken) { + setCustomerToken(accessToken) + } + + return null + }, + useHook: + ({ fetch }) => + () => { + const { revalidate } = useCustomer() + + return useCallback( + async function login(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/swell/auth/use-logout.tsx b/framework/swell/auth/use-logout.tsx new file mode 100644 index 00000000..dba4c7ed --- /dev/null +++ b/framework/swell/auth/use-logout.tsx @@ -0,0 +1,38 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import useLogout, { UseLogout } from '@commerce/auth/use-logout' +import useCustomer from '../customer/use-customer' +import { getCustomerToken, setCustomerToken } from '../utils/customer-token' + +export default useLogout as UseLogout<typeof handler> + +export const handler: MutationHook<null> = { + fetchOptions: { + query: 'account', + method: 'logout', + }, + async fetcher({ options, fetch }) { + await fetch({ + ...options, + variables: { + customerAccessToken: getCustomerToken(), + }, + }) + setCustomerToken(null) + return null + }, + useHook: + ({ fetch }) => + () => { + const { mutate } = useCustomer() + + return useCallback( + async function logout() { + const data = await fetch() + await mutate(null, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/swell/auth/use-signup.tsx b/framework/swell/auth/use-signup.tsx new file mode 100644 index 00000000..de01a17a --- /dev/null +++ b/framework/swell/auth/use-signup.tsx @@ -0,0 +1,67 @@ +import { useCallback } from 'react' +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useSignup, { UseSignup } from '@commerce/auth/use-signup' +import useCustomer from '../customer/use-customer' +import { CustomerCreateInput } from '../schema' + +import handleLogin from '../utils/handle-login' + +export default useSignup as UseSignup<typeof handler> + +export const handler: MutationHook< + null, + {}, + CustomerCreateInput, + CustomerCreateInput +> = { + fetchOptions: { + query: 'account', + method: 'create', + }, + async fetcher({ + input: { firstName, lastName, email, password }, + options, + fetch, + }) { + if (!(firstName && lastName && email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to signup', + }) + } + const data = await fetch({ + ...options, + variables: { + first_name: firstName, + last_name: lastName, + email, + password, + }, + }) + + try { + const loginData = await fetch({ + query: 'account', + method: 'login', + variables: [email, password], + }) + handleLogin(loginData) + } catch (error) {} + return data + }, + useHook: + ({ fetch }) => + () => { + const { revalidate } = useCustomer() + + return useCallback( + async function signup(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/swell/cart/index.ts b/framework/swell/cart/index.ts new file mode 100644 index 00000000..3d288b1d --- /dev/null +++ b/framework/swell/cart/index.ts @@ -0,0 +1,3 @@ +export { default as useCart } from './use-cart' +export { default as useAddItem } from './use-add-item' +export { default as useRemoveItem } from './use-remove-item' diff --git a/framework/swell/cart/use-add-item.tsx b/framework/swell/cart/use-add-item.tsx new file mode 100644 index 00000000..e69ffd1f --- /dev/null +++ b/framework/swell/cart/use-add-item.tsx @@ -0,0 +1,61 @@ +import type { MutationHook } from '@commerce/utils/types' +import { CommerceError } from '@commerce/utils/errors' +import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' +import useCart from './use-cart' +import { Cart, CartItemBody } from '../types' +import { checkoutToCart } from './utils' +import { getCheckoutId } from '../utils' +import { useCallback } from 'react' + +export default useAddItem as UseAddItem<typeof handler> + +export const handler: MutationHook<Cart, {}, CartItemBody> = { + fetchOptions: { + query: 'cart', + method: 'addItem', + }, + async fetcher({ input: item, options, fetch }) { + if ( + item.quantity && + (!Number.isInteger(item.quantity) || item.quantity! < 1) + ) { + throw new CommerceError({ + message: 'The item quantity has to be a valid integer greater than 0', + }) + } + const variables: { + product_id: string + variant_id?: string + checkoutId?: string + quantity?: number + } = { + checkoutId: getCheckoutId(), + product_id: item.productId, + quantity: item.quantity, + } + if (item.productId !== item.variantId) { + variables.variant_id = item.variantId + } + + const response = await fetch({ + ...options, + variables, + }) + + return checkoutToCart(response) as any + }, + useHook: + ({ fetch }) => + () => { + const { mutate } = useCart() + + return useCallback( + async function addItem(input) { + const data = await fetch({ input }) + await mutate(data, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/swell/cart/use-cart.tsx b/framework/swell/cart/use-cart.tsx new file mode 100644 index 00000000..2abf8395 --- /dev/null +++ b/framework/swell/cart/use-cart.tsx @@ -0,0 +1,39 @@ +import useCart, { UseCart } from '@commerce/cart/use-cart' +import { Cart } from '@commerce/types' +import { SWRHook } from '@commerce/utils/types' +import { useMemo } from 'react' +import { normalizeCart } from '../utils/normalize' +import { checkoutCreate, checkoutToCart } from './utils' + +export default useCart as UseCart<typeof handler> + +export const handler: SWRHook<Cart | null, {}, any, { isEmpty?: boolean }> = { + fetchOptions: { + query: 'cart', + method: 'get', + }, + async fetcher({ fetch }) { + const cart = await checkoutCreate(fetch) + + return cart ? normalizeCart(cart) : null + }, + useHook: + ({ useData }) => + (input) => { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, + }) + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} diff --git a/framework/swell/cart/use-remove-item.tsx b/framework/swell/cart/use-remove-item.tsx new file mode 100644 index 00000000..91d5aab3 --- /dev/null +++ b/framework/swell/cart/use-remove-item.tsx @@ -0,0 +1,67 @@ +import { useCallback } from 'react' + +import type { + MutationHookContext, + HookFetcherContext, +} from '@commerce/utils/types' + +import { ValidationError } from '@commerce/utils/errors' + +import useRemoveItem, { + RemoveItemInput as RemoveItemInputBase, + UseRemoveItem, +} from '@commerce/cart/use-remove-item' + +import useCart from './use-cart' +import { checkoutToCart } from './utils' +import { Cart, LineItem } from '../types' +import { RemoveCartItemBody } from '@commerce/types' + +export type RemoveItemFn<T = any> = T extends LineItem + ? (input?: RemoveItemInput<T>) => Promise<Cart | null> + : (input: RemoveItemInput<T>) => Promise<Cart | null> + +export type RemoveItemInput<T = any> = T extends LineItem + ? Partial<RemoveItemInputBase> + : RemoveItemInputBase + +export default useRemoveItem as UseRemoveItem<typeof handler> + +export const handler = { + fetchOptions: { + query: 'cart', + method: 'removeItem', + }, + async fetcher({ + input: { itemId }, + options, + fetch, + }: HookFetcherContext<RemoveCartItemBody>) { + const response = await fetch({ + ...options, + variables: [itemId], + }) + return checkoutToCart(response) + }, + useHook: + ({ fetch }: MutationHookContext<Cart | null, RemoveCartItemBody>) => + <T extends LineItem | undefined = undefined>(ctx: { item?: T } = {}) => { + const { item } = ctx + const { mutate } = useCart() + const removeItem: RemoveItemFn<LineItem> = async (input) => { + const itemId = input?.id ?? item?.id + + if (!itemId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ input: { itemId } }) + await mutate(data, false) + return data + } + + return useCallback(removeItem as RemoveItemFn<T>, [fetch, mutate]) + }, +} diff --git a/framework/swell/cart/use-update-item.tsx b/framework/swell/cart/use-update-item.tsx new file mode 100644 index 00000000..8942eb79 --- /dev/null +++ b/framework/swell/cart/use-update-item.tsx @@ -0,0 +1,93 @@ +import { useCallback } from 'react' +import debounce from 'lodash.debounce' +import type { + HookFetcherContext, + MutationHookContext, +} from '@commerce/utils/types' +import { ValidationError } from '@commerce/utils/errors' +import useUpdateItem, { + UpdateItemInput as UpdateItemInputBase, + UseUpdateItem, +} from '@commerce/cart/use-update-item' + +import useCart from './use-cart' +import { handler as removeItemHandler } from './use-remove-item' +import type { Cart, LineItem, UpdateCartItemBody } from '../types' +import { checkoutToCart } from './utils' + +export type UpdateItemInput<T = any> = T extends LineItem + ? Partial<UpdateItemInputBase<LineItem>> + : UpdateItemInputBase<LineItem> + +export default useUpdateItem as UseUpdateItem<typeof handler> + +export const handler = { + fetchOptions: { + query: 'cart', + method: 'updateItem', + }, + async fetcher({ + input: { itemId, item }, + options, + fetch, + }: HookFetcherContext<UpdateCartItemBody>) { + if (Number.isInteger(item.quantity)) { + // Also allow the update hook to remove an item if the quantity is lower than 1 + if (item.quantity! < 1) { + return removeItemHandler.fetcher({ + options: removeItemHandler.fetchOptions, + input: { itemId }, + fetch, + }) + } + } else if (item.quantity) { + throw new ValidationError({ + message: 'The item quantity has to be a valid integer', + }) + } + const response = await fetch({ + ...options, + variables: [itemId, { quantity: item.quantity }], + }) + + return checkoutToCart(response) + }, + useHook: + ({ fetch }: MutationHookContext<Cart | null, UpdateCartItemBody>) => + <T extends LineItem | undefined = undefined>( + ctx: { + item?: T + wait?: number + } = {} + ) => { + const { item } = ctx + const { mutate, data: cartData } = useCart() as any + + return useCallback( + debounce(async (input: UpdateItemInput<T>) => { + const itemId = cartData.lineItems[0].id + const productId = cartData.lineItems[0].productId + const variantId = cartData.lineItems[0].variant.id + if (!itemId || !productId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + + const data = await fetch({ + input: { + item: { + productId, + variantId, + quantity: input.quantity, + }, + itemId, + }, + }) + await mutate(data, false) + return data + }, ctx.wait ?? 500), + [fetch, mutate] + ) + }, +} diff --git a/framework/swell/cart/utils/checkout-create.ts b/framework/swell/cart/utils/checkout-create.ts new file mode 100644 index 00000000..5ee3833c --- /dev/null +++ b/framework/swell/cart/utils/checkout-create.ts @@ -0,0 +1,28 @@ +import { SWELL_CHECKOUT_URL_COOKIE } from '../../const' + +import Cookies from 'js-cookie' + +export const checkoutCreate = async (fetch: any) => { + const cart = await fetch({ + query: 'cart', + method: 'get', + }) + + if (!cart) { + const cart = await fetch({ + query: 'cart', + method: 'setItems', + variables: [[]], + }) + } + + const checkoutUrl = cart?.checkout_url + + if (checkoutUrl) { + Cookies.set(SWELL_CHECKOUT_URL_COOKIE, checkoutUrl) + } + + return cart +} + +export default checkoutCreate diff --git a/framework/swell/cart/utils/checkout-to-cart.ts b/framework/swell/cart/utils/checkout-to-cart.ts new file mode 100644 index 00000000..d6dfda20 --- /dev/null +++ b/framework/swell/cart/utils/checkout-to-cart.ts @@ -0,0 +1,26 @@ +import { Cart } from '../../types' +import { CommerceError } from '@commerce/utils/errors' + +import { + CheckoutLineItemsAddPayload, + CheckoutLineItemsRemovePayload, + CheckoutLineItemsUpdatePayload, + Maybe, +} from '../../schema' +import { normalizeCart } from '../../utils' + +export type CheckoutPayload = + | CheckoutLineItemsAddPayload + | CheckoutLineItemsUpdatePayload + | CheckoutLineItemsRemovePayload + +const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => { + if (!checkoutPayload) { + throw new CommerceError({ + message: 'Invalid response from Swell', + }) + } + return normalizeCart(checkoutPayload as any) +} + +export default checkoutToCart diff --git a/framework/swell/cart/utils/fetcher.ts b/framework/swell/cart/utils/fetcher.ts new file mode 100644 index 00000000..2e7ae15d --- /dev/null +++ b/framework/swell/cart/utils/fetcher.ts @@ -0,0 +1,33 @@ +import { HookFetcherFn } from '@commerce/utils/types' +import { Cart } from '@commerce/types' +// import { checkoutCreate, checkoutToCart } from '.' +import { FetchCartInput } from '@commerce/cart/use-cart' +import { data } from 'autoprefixer' +import { normalizeCart } from '../../utils' + +const fetcher: HookFetcherFn<Cart | null, FetchCartInput> = async ({ + options, + // input: { cartId: checkoutId }, + fetch, +}) => { + let checkout + + // if (checkoutId) { + const data = await fetch({ + query: 'cart', + method: 'get', + // variables: { category: categoryId }, + }) + // checkout = data.node + // } + + // if (checkout?.completedAt || !checkoutId) { + // checkout = await checkoutCreate(fetch) + // } + + // TODO: Fix this type + // return checkoutToCart({ checkout } as any) + return normalizeCart(data) +} + +export default fetcher diff --git a/framework/swell/cart/utils/index.ts b/framework/swell/cart/utils/index.ts new file mode 100644 index 00000000..20d04955 --- /dev/null +++ b/framework/swell/cart/utils/index.ts @@ -0,0 +1,2 @@ +export { default as checkoutToCart } from './checkout-to-cart' +export { default as checkoutCreate } from './checkout-create' diff --git a/framework/swell/commerce.config.json b/framework/swell/commerce.config.json new file mode 100644 index 00000000..01c9bf91 --- /dev/null +++ b/framework/swell/commerce.config.json @@ -0,0 +1,6 @@ +{ + "provider": "swell", + "features": { + "wishlist": false + } +} diff --git a/framework/swell/common/get-all-pages.ts b/framework/swell/common/get-all-pages.ts new file mode 100644 index 00000000..8d0b9cf3 --- /dev/null +++ b/framework/swell/common/get-all-pages.ts @@ -0,0 +1,37 @@ +import { getConfig, SwellConfig } from '../api' + +type Variables = { + first?: number +} + +type ReturnType = { + pages: Page[] +} + +export type Page = { + id: string + name: string + url: string + sort_order?: number + body: string +} + +const getAllPages = async (options?: { + variables?: Variables + config: SwellConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables = { first: 250 } } = options ?? {} + config = getConfig(config) + const { locale, fetch } = config + const data = await fetch('content', 'list', ['pages']) + const pages = + data?.results?.map(({ slug, ...rest }: { slug: string }) => ({ + url: `/${locale}/${slug}`, + ...rest, + })) ?? [] + + return { pages } +} + +export default getAllPages diff --git a/framework/swell/common/get-page.ts b/framework/swell/common/get-page.ts new file mode 100644 index 00000000..dca317a1 --- /dev/null +++ b/framework/swell/common/get-page.ts @@ -0,0 +1,33 @@ +import { getConfig, SwellConfig } from '../api' +import { Page } from './get-all-pages' + +type Variables = { + id: string +} + +export type GetPageResult<T extends { page?: any } = { page?: Page }> = T + +const getPage = async (options: { + variables: Variables + config: SwellConfig + preview?: boolean +}): Promise<GetPageResult> => { + let { config, variables } = options ?? {} + + config = getConfig(config) + const { locale } = config + const { id } = variables + const result = await config.fetch('content', 'get', ['pages', id]) + const page = result + + return { + page: page + ? { + ...page, + url: `/${locale}/${page.slug}`, + } + : null, + } +} + +export default getPage diff --git a/framework/swell/common/get-site-info.ts b/framework/swell/common/get-site-info.ts new file mode 100644 index 00000000..e44d9cc0 --- /dev/null +++ b/framework/swell/common/get-site-info.ts @@ -0,0 +1,31 @@ +import getCategories, { Category } from '../utils/get-categories' +import getVendors, { Brands } from '../utils/get-vendors' + +import { getConfig, SwellConfig } from '../api' + +export type GetSiteInfoResult< + T extends { categories: any[]; brands: any[] } = { + categories: Category[] + brands: Brands + } +> = T + +const getSiteInfo = async (options?: { + variables?: any + config: SwellConfig + preview?: boolean +}): Promise<GetSiteInfoResult> => { + let { config } = options ?? {} + + config = getConfig(config) + + const categories = await getCategories(config) + const brands = await getVendors(config) + + return { + categories, + brands, + } +} + +export default getSiteInfo diff --git a/framework/swell/const.ts b/framework/swell/const.ts new file mode 100644 index 00000000..66919429 --- /dev/null +++ b/framework/swell/const.ts @@ -0,0 +1,13 @@ +export const SWELL_CHECKOUT_ID_COOKIE = 'SWELL_checkoutId' + +export const SWELL_CHECKOUT_URL_COOKIE = 'swell_checkoutUrl' + +export const SWELL_CUSTOMER_TOKEN_COOKIE = 'swell_customerToken' + +export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SWELL_STORE_DOMAIN + +export const SWELL_COOKIE_EXPIRE = 30 + +export const SWELL_STORE_ID = process.env.NEXT_PUBLIC_SWELL_STORE_ID + +export const SWELL_PUBLIC_KEY = process.env.NEXT_PUBLIC_SWELL_PUBLIC_KEY diff --git a/framework/swell/customer/index.ts b/framework/swell/customer/index.ts new file mode 100644 index 00000000..6c903ecc --- /dev/null +++ b/framework/swell/customer/index.ts @@ -0,0 +1 @@ +export { default as useCustomer } from './use-customer' diff --git a/framework/swell/customer/use-customer.tsx b/framework/swell/customer/use-customer.tsx new file mode 100644 index 00000000..1b531887 --- /dev/null +++ b/framework/swell/customer/use-customer.tsx @@ -0,0 +1,52 @@ +import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' +import { Customer } from '@commerce/types' +import { SWRHook } from '@commerce/utils/types' +import { normalizeCustomer } from '../utils/normalize' + +export default useCustomer as UseCustomer<typeof handler> + +export const handler: SWRHook<Customer | null> = { + fetchOptions: { + query: 'account', + method: 'get', + }, + async fetcher({ options, fetch }) { + const data = await fetch<any | null>({ + ...options, + }) + return data ? normalizeCustomer(data) : null + }, + useHook: + ({ useData }) => + (input) => { + return useData({ + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions, + }, + }) + }, +} + +// 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; diff --git a/framework/swell/fetcher.ts b/framework/swell/fetcher.ts new file mode 100644 index 00000000..f18dcf66 --- /dev/null +++ b/framework/swell/fetcher.ts @@ -0,0 +1,28 @@ +import { Fetcher } from '@commerce/utils/types' +import { handleFetchResponse } from './utils' +import { swellConfig } from './index' +import { CommerceError } from '@commerce/utils/errors' + +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) + return handleFetchResponse(response) + } else { + const response = await swell[query!][method](variables) + return handleFetchResponse(response) + } + } + + if (query && query in swell) { + return await callSwell() + } else { + throw new CommerceError({ message: 'Invalid query argument!' }) + } +} + +export default fetcher diff --git a/framework/swell/index.tsx b/framework/swell/index.tsx new file mode 100644 index 00000000..28f60b39 --- /dev/null +++ b/framework/swell/index.tsx @@ -0,0 +1,47 @@ +import * as React from 'react' +import swell from 'swell-js' +import { ReactNode } from 'react' + +import { + CommerceConfig, + CommerceProvider as CoreCommerceProvider, + useCommerce as useCoreCommerce, +} from '@commerce' + +import { swellProvider, SwellProvider } from './provider' +import { + SWELL_CHECKOUT_ID_COOKIE, + SWELL_STORE_ID, + SWELL_PUBLIC_KEY, +} from './const' +swell.init(SWELL_STORE_ID, SWELL_PUBLIC_KEY) + +export { swellProvider } +export type { SwellProvider } + +export const swellConfig: any = { + locale: 'en-us', + cartCookie: SWELL_CHECKOUT_ID_COOKIE, + swell, +} + +export type SwellConfig = Partial<CommerceConfig> + +export type SwellProps = { + children?: ReactNode + locale: string +} & SwellConfig + +export function CommerceProvider({ children, ...config }: SwellProps) { + return ( + <CoreCommerceProvider + // TODO: Fix this type + provider={swellProvider as any} + config={{ ...swellConfig, ...config }} + > + {children} + </CoreCommerceProvider> + ) +} + +export const useCommerce = () => useCoreCommerce() diff --git a/framework/swell/next.config.js b/framework/swell/next.config.js new file mode 100644 index 00000000..f6ac3834 --- /dev/null +++ b/framework/swell/next.config.js @@ -0,0 +1,8 @@ +const commerce = require('./commerce.config.json') + +module.exports = { + commerce, + images: { + domains: ['cdn.schema.io'], + }, +} diff --git a/framework/swell/product/get-all-collections.ts b/framework/swell/product/get-all-collections.ts new file mode 100644 index 00000000..6b82ce44 --- /dev/null +++ b/framework/swell/product/get-all-collections.ts @@ -0,0 +1,28 @@ +import { CollectionEdge } from '../schema' +import { getConfig, SwellConfig } from '../api' + +const getAllCollections = async (options?: { + variables?: any + config: SwellConfig + preview?: boolean +}) => { + let { config, variables = { limit: 25 } } = options ?? {} + config = getConfig(config) + + const response = await config.fetch('categories', 'list', { variables }) + const edges = response.results ?? [] + + const categories = edges.map( + ({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({ + entityId, + name, + path: `/${handle}`, + }) + ) + + return { + categories, + } +} + +export default getAllCollections diff --git a/framework/swell/product/get-all-product-paths.ts b/framework/swell/product/get-all-product-paths.ts new file mode 100644 index 00000000..933eb73b --- /dev/null +++ b/framework/swell/product/get-all-product-paths.ts @@ -0,0 +1,39 @@ +import { SwellProduct } from '../types' +import { getConfig, SwellConfig } from '../api' + +type ProductPath = { + path: string +} + +export type ProductPathNode = { + node: ProductPath +} + +type ReturnType = { + products: ProductPathNode[] +} + +const getAllProductPaths = async (options?: { + variables?: any + config?: SwellConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables = [{ limit: 100 }] } = options ?? {} + config = getConfig(config) + + const { results } = await config.fetch('products', 'list', [ + { + limit: variables.first, + }, + ]) + + return { + products: results?.map(({ slug: handle }: SwellProduct) => ({ + node: { + path: `/${handle}`, + }, + })), + } +} + +export default getAllProductPaths diff --git a/framework/swell/product/get-all-products.ts b/framework/swell/product/get-all-products.ts new file mode 100644 index 00000000..c0746efc --- /dev/null +++ b/framework/swell/product/get-all-products.ts @@ -0,0 +1,36 @@ +import { getConfig, SwellConfig } from '../api' +import { normalizeProduct } from '../utils/normalize' +import { Product } from '@commerce/types' +import { SwellProduct } from '../types' + +type Variables = { + first?: number + field?: string +} + +type ReturnType = { + products: Product[] +} + +const getAllProducts = async (options: { + variables?: Variables + config?: SwellConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables = { first: 250 } } = options ?? {} + config = getConfig(config) + const { results } = await config.fetch('products', 'list', [ + { + limit: variables.first, + }, + ]) + const products = results.map((product: SwellProduct) => + normalizeProduct(product) + ) + + return { + products, + } +} + +export default getAllProducts diff --git a/framework/swell/product/get-product.ts b/framework/swell/product/get-product.ts new file mode 100644 index 00000000..0d75a57c --- /dev/null +++ b/framework/swell/product/get-product.ts @@ -0,0 +1,32 @@ +import { GraphQLFetcherResult } from '@commerce/api' +import { getConfig, SwellConfig } from '../api' +import { normalizeProduct } from '../utils' + +type Variables = { + slug: string +} + +type ReturnType = { + product: any +} + +const getProduct = async (options: { + variables: Variables + config: SwellConfig + preview?: boolean +}): Promise<ReturnType> => { + let { config, variables } = options ?? {} + config = getConfig(config) + + const product = await config.fetch('products', 'get', [variables.slug]) + + if (product && product.variants) { + product.variants = product.variants?.results + } + + return { + product: product ? normalizeProduct(product) : null, + } +} + +export default getProduct diff --git a/framework/swell/product/use-price.tsx b/framework/swell/product/use-price.tsx new file mode 100644 index 00000000..0174faf5 --- /dev/null +++ b/framework/swell/product/use-price.tsx @@ -0,0 +1,2 @@ +export * from '@commerce/product/use-price' +export { default } from '@commerce/product/use-price' diff --git a/framework/swell/product/use-search.tsx b/framework/swell/product/use-search.tsx new file mode 100644 index 00000000..b966c869 --- /dev/null +++ b/framework/swell/product/use-search.tsx @@ -0,0 +1,73 @@ +import { SWRHook } from '@commerce/utils/types' +import useSearch, { UseSearch } from '@commerce/product/use-search' + +import { normalizeProduct } from '../utils' + +import { Product } from '@commerce/types' + +import { SwellProduct } from '../types' + +export default useSearch as UseSearch<typeof handler> + +export type SearchProductsInput = { + search?: string + categoryId?: string + brandId?: string + sort?: string +} + +export type SearchProductsData = { + products: Product[] + found: boolean +} + +export const handler: SWRHook< + SearchProductsData, + SearchProductsInput, + SearchProductsInput +> = { + fetchOptions: { + query: 'products', // String(Math.random()), + method: 'list', + }, + async fetcher({ input, options, fetch }) { + const sortMap = new Map([ + ['latest-desc', ''], + ['price-asc', 'price_asc'], + ['price-desc', 'price_desc'], + ['trending-desc', 'popularity'], + ]) + const { categoryId, search, sort = 'latest-desc' } = input + const mappedSort = sortMap.get(sort) + const { results, count: found } = await fetch({ + query: 'products', + method: 'list', + variables: { category: categoryId, search, sort: mappedSort }, + }) + + const products = results.map((product: SwellProduct) => + normalizeProduct(product) + ) + + return { + products, + found, + } + }, + 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/framework/swell/provider.ts b/framework/swell/provider.ts new file mode 100644 index 00000000..0bcbd788 --- /dev/null +++ b/framework/swell/provider.ts @@ -0,0 +1,31 @@ +import { SWELL_CHECKOUT_URL_COOKIE, STORE_DOMAIN } from './const' + +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' + +import fetcher from './fetcher' + +export const swellProvider = { + locale: 'en-us', + cartCookie: SWELL_CHECKOUT_URL_COOKIE, + storeDomain: STORE_DOMAIN, + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, + features: { + wishlist: false, + }, +} + +export type SwellProvider = typeof swellProvider diff --git a/framework/swell/schema.d.ts b/framework/swell/schema.d.ts new file mode 100644 index 00000000..e77d3c8d --- /dev/null +++ b/framework/swell/schema.d.ts @@ -0,0 +1,5002 @@ +export type Maybe<T> = T | null +export type Exact<T extends { [key: string]: unknown }> = { + [K in keyof T]: T[K] +} +export type MakeOptional<T, K extends keyof T> = Omit<T, K> & + { [SubKey in K]?: Maybe<T[SubKey]> } +export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & + { [SubKey in K]: Maybe<T[SubKey]> } +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string + String: string + Boolean: boolean + Int: number + Float: number + /** An ISO-8601 encoded UTC date time string. Example value: `"2019-07-03T20:47:55Z"`. */ + DateTime: any + /** A signed decimal number, which supports arbitrary precision and is serialized as a string. Example value: `"29.99"`. */ + Decimal: any + /** A string containing HTML code. Example value: `"<p>Grey cotton knit sweater.</p>"`. */ + HTML: any + /** A monetary value string. Example value: `"100.57"`. */ + Money: any + /** + * An RFC 3986 and RFC 3987 compliant URI string. + * + * Example value: `"https://johns-apparel.myshopify.com"`. + * + */ + URL: any +} + +/** A version of the API. */ +export type ApiVersion = { + __typename?: 'ApiVersion' + /** The human-readable name of the version. */ + displayName: Scalars['String'] + /** The unique identifier of an ApiVersion. All supported API versions have a date-based (YYYY-MM) or `unstable` handle. */ + handle: Scalars['String'] + /** Whether the version is supported by Shopify. */ + supported: Scalars['Boolean'] +} + +/** Details about the gift card used on the checkout. */ +export type AppliedGiftCard = Node & { + __typename?: 'AppliedGiftCard' + /** + * The amount that was taken from the gift card by applying it. + * @deprecated Use `amountUsedV2` instead + */ + amountUsed: Scalars['Money'] + /** The amount that was taken from the gift card by applying it. */ + amountUsedV2: MoneyV2 + /** + * The amount left on the gift card. + * @deprecated Use `balanceV2` instead + */ + balance: Scalars['Money'] + /** The amount left on the gift card. */ + balanceV2: MoneyV2 + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The last characters of the gift card. */ + lastCharacters: Scalars['String'] + /** The amount that was applied to the checkout in its currency. */ + presentmentAmountUsed: MoneyV2 +} + +/** An article in an online store blog. */ +export type Article = Node & { + __typename?: 'Article' + /** + * The article's author. + * @deprecated Use `authorV2` instead + */ + author: ArticleAuthor + /** The article's author. */ + authorV2?: Maybe<ArticleAuthor> + /** The blog that the article belongs to. */ + blog: Blog + /** List of comments posted on the article. */ + comments: CommentConnection + /** Stripped content of the article, single line with HTML tags removed. */ + content: Scalars['String'] + /** The content of the article, complete with HTML formatting. */ + contentHtml: Scalars['HTML'] + /** Stripped excerpt of the article, single line with HTML tags removed. */ + excerpt?: Maybe<Scalars['String']> + /** The excerpt of the article, complete with HTML formatting. */ + excerptHtml?: Maybe<Scalars['HTML']> + /** A human-friendly unique string for the Article automatically generated from its title. */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The image associated with the article. */ + image?: Maybe<Image> + /** The date and time when the article was published. */ + publishedAt: Scalars['DateTime'] + /** The article’s SEO information. */ + seo?: Maybe<Seo> + /** A categorization that a article can be tagged with. */ + tags: Array<Scalars['String']> + /** The article’s name. */ + title: Scalars['String'] + /** The url pointing to the article accessible from the web. */ + url: Scalars['URL'] +} + +/** An article in an online store blog. */ +export type ArticleCommentsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** An article in an online store blog. */ +export type ArticleContentArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** An article in an online store blog. */ +export type ArticleExcerptArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** An article in an online store blog. */ +export type ArticleImageArgs = { + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> +} + +/** The author of an article. */ +export type ArticleAuthor = { + __typename?: 'ArticleAuthor' + /** The author's bio. */ + bio?: Maybe<Scalars['String']> + /** The author’s email. */ + email: Scalars['String'] + /** The author's first name. */ + firstName: Scalars['String'] + /** The author's last name. */ + lastName: Scalars['String'] + /** The author's full name. */ + name: Scalars['String'] +} + +/** An auto-generated type for paginating through multiple Articles. */ +export type ArticleConnection = { + __typename?: 'ArticleConnection' + /** A list of edges. */ + edges: Array<ArticleEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Article and a cursor during pagination. */ +export type ArticleEdge = { + __typename?: 'ArticleEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ArticleEdge. */ + node: Article +} + +/** The set of valid sort keys for the Article query. */ +export enum ArticleSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `blog_title` value. */ + BlogTitle = 'BLOG_TITLE', + /** Sort by the `author` value. */ + Author = 'AUTHOR', + /** Sort by the `updated_at` value. */ + UpdatedAt = 'UPDATED_AT', + /** Sort by the `published_at` value. */ + PublishedAt = 'PUBLISHED_AT', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** Represents a generic custom attribute. */ +export type Attribute = { + __typename?: 'Attribute' + /** Key or name of the attribute. */ + key: Scalars['String'] + /** Value of the attribute. */ + value?: Maybe<Scalars['String']> +} + +/** Specifies the input fields required for an attribute. */ +export type AttributeInput = { + /** Key or name of the attribute. */ + key: Scalars['String'] + /** Value of the attribute. */ + value: Scalars['String'] +} + +/** Automatic discount applications capture the intentions of a discount that was automatically applied. */ +export type AutomaticDiscountApplication = DiscountApplication & { + __typename?: 'AutomaticDiscountApplication' + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The title of the application. */ + title: Scalars['String'] + /** The value of the discount application. */ + value: PricingValue +} + +/** A collection of available shipping rates for a checkout. */ +export type AvailableShippingRates = { + __typename?: 'AvailableShippingRates' + /** + * Whether or not the shipping rates are ready. + * The `shippingRates` field is `null` when this value is `false`. + * This field should be polled until its value becomes `true`. + */ + ready: Scalars['Boolean'] + /** The fetched shipping rates. `null` until the `ready` field is `true`. */ + shippingRates?: Maybe<Array<ShippingRate>> +} + +/** An online store blog. */ +export type Blog = Node & { + __typename?: 'Blog' + /** Find an article by its handle. */ + articleByHandle?: Maybe<Article> + /** List of the blog's articles. */ + articles: ArticleConnection + /** The authors who have contributed to the blog. */ + authors: Array<ArticleAuthor> + /** A human-friendly unique string for the Blog automatically generated from its title. */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The blog's SEO information. */ + seo?: Maybe<Seo> + /** The blogs’s title. */ + title: Scalars['String'] + /** The url pointing to the blog accessible from the web. */ + url: Scalars['URL'] +} + +/** An online store blog. */ +export type BlogArticleByHandleArgs = { + handle: Scalars['String'] +} + +/** An online store blog. */ +export type BlogArticlesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ArticleSortKeys> + query?: Maybe<Scalars['String']> +} + +/** An auto-generated type for paginating through multiple Blogs. */ +export type BlogConnection = { + __typename?: 'BlogConnection' + /** A list of edges. */ + edges: Array<BlogEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Blog and a cursor during pagination. */ +export type BlogEdge = { + __typename?: 'BlogEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of BlogEdge. */ + node: Blog +} + +/** The set of valid sort keys for the Blog query. */ +export enum BlogSortKeys { + /** Sort by the `handle` value. */ + Handle = 'HANDLE', + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** Card brand, such as Visa or Mastercard, which can be used for payments. */ +export enum CardBrand { + /** Visa */ + Visa = 'VISA', + /** Mastercard */ + Mastercard = 'MASTERCARD', + /** Discover */ + Discover = 'DISCOVER', + /** American Express */ + AmericanExpress = 'AMERICAN_EXPRESS', + /** Diners Club */ + DinersClub = 'DINERS_CLUB', + /** JCB */ + Jcb = 'JCB', +} + +/** A container for all the information required to checkout items and pay. */ +export type Checkout = { + name: string + currency: string + support_email: string + fields: any[] + scripts: any[] + accounts: string + email_optin: boolean + terms_policy?: string + refund_policy?: string + privacy_policy?: string + theme?: stirng + countries: any[] + currencies: any[] + payment_methods: any[] + coupons: boolean + giftcards: boolean + + // __typename?: 'Checkout' + // /** The gift cards used on the checkout. */ + // appliedGiftCards: Array<AppliedGiftCard> + // /** + // * The available shipping rates for this Checkout. + // * Should only be used when checkout `requiresShipping` is `true` and + // * the shipping address is valid. + // */ + // availableShippingRates?: Maybe<AvailableShippingRates> + // /** The date and time when the checkout was completed. */ + // completedAt?: Maybe<Scalars['DateTime']> + // /** The date and time when the checkout was created. */ + // createdAt: Scalars['DateTime'] + // /** The currency code for the Checkout. */ + // currencyCode: CurrencyCode + // /** A list of extra information that is added to the checkout. */ + // customAttributes: Array<Attribute> + // /** + // * The customer associated with the checkout. + // * @deprecated This field will always return null. If you have an authentication token for the customer, you can use the `customer` field on the query root to retrieve it. + // */ + // customer?: Maybe<Customer> + // /** Discounts that have been applied on the checkout. */ + // discountApplications: DiscountApplicationConnection + // /** The email attached to this checkout. */ + // email?: Maybe<Scalars['String']> + // /** Globally unique identifier. */ + // id: Scalars['ID'] + // /** A list of line item objects, each one containing information about an item in the checkout. */ + // lineItems: CheckoutLineItemConnection + // /** The sum of all the prices of all the items in the checkout. Duties, taxes, shipping and discounts excluded. */ + // lineItemsSubtotalPrice: MoneyV2 + // /** The note associated with the checkout. */ + // note?: Maybe<Scalars['String']> + // /** The resulting order from a paid checkout. */ + // order?: Maybe<Order> + // /** The Order Status Page for this Checkout, null when checkout is not completed. */ + // orderStatusUrl?: Maybe<Scalars['URL']> + // /** + // * The amount left to be paid. This is equal to the cost of the line items, taxes and shipping minus discounts and gift cards. + // * @deprecated Use `paymentDueV2` instead + // */ + // paymentDue: Scalars['Money'] + // /** The amount left to be paid. This is equal to the cost of the line items, duties, taxes and shipping minus discounts and gift cards. */ + // paymentDueV2: MoneyV2 + // /** + // * Whether or not the Checkout is ready and can be completed. Checkouts may + // * have asynchronous operations that can take time to finish. If you want + // * to complete a checkout or ensure all the fields are populated and up to + // * date, polling is required until the value is true. + // */ + // ready: Scalars['Boolean'] + // /** States whether or not the fulfillment requires shipping. */ + // requiresShipping: Scalars['Boolean'] + // /** The shipping address to where the line items will be shipped. */ + // shippingAddress?: Maybe<MailingAddress> + // /** The discounts that have been allocated onto the shipping line by discount applications. */ + // shippingDiscountAllocations: Array<DiscountAllocation> + // /** Once a shipping rate is selected by the customer it is transitioned to a `shipping_line` object. */ + // shippingLine?: Maybe<ShippingRate> + // /** + // * Price of the checkout before shipping and taxes. + // * @deprecated Use `subtotalPriceV2` instead + // */ + // subtotalPrice: Scalars['Money'] + // /** Price of the checkout before duties, shipping and taxes. */ + // subtotalPriceV2: MoneyV2 + // /** Specifies if the Checkout is tax exempt. */ + // taxExempt: Scalars['Boolean'] + // /** Specifies if taxes are included in the line item and shipping line prices. */ + // taxesIncluded: Scalars['Boolean'] + // /** + // * The sum of all the prices of all the items in the checkout, taxes and discounts included. + // * @deprecated Use `totalPriceV2` instead + // */ + // totalPrice: Scalars['Money'] + // /** The sum of all the prices of all the items in the checkout, duties, taxes and discounts included. */ + // totalPriceV2: MoneyV2 + // /** + // * The sum of all the taxes applied to the line items and shipping lines in the checkout. + // * @deprecated Use `totalTaxV2` instead + // */ + // totalTax: Scalars['Money'] + // /** The sum of all the taxes applied to the line items and shipping lines in the checkout. */ + // totalTaxV2: MoneyV2 + // /** The date and time when the checkout was last updated. */ + // updatedAt: Scalars['DateTime'] + // /** The url pointing to the checkout accessible from the web. */ + // webUrl: Scalars['URL'] +} + +/** A container for all the information required to checkout items and pay. */ +export type CheckoutDiscountApplicationsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** A container for all the information required to checkout items and pay. */ +export type CheckoutLineItemsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** Specifies the fields required to update a checkout's attributes. */ +export type CheckoutAttributesUpdateInput = { + /** The text of an optional note that a shop owner can attach to the checkout. */ + note?: Maybe<Scalars['String']> + /** A list of extra information that is added to the checkout. */ + customAttributes?: Maybe<Array<AttributeInput>> + /** + * Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + * The required attributes are city, province, and country. + * Full validation of the addresses is still done at complete time. + */ + allowPartialAddresses?: Maybe<Scalars['Boolean']> +} + +/** Return type for `checkoutAttributesUpdate` mutation. */ +export type CheckoutAttributesUpdatePayload = { + __typename?: 'CheckoutAttributesUpdatePayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to update a checkout's attributes. */ +export type CheckoutAttributesUpdateV2Input = { + /** The text of an optional note that a shop owner can attach to the checkout. */ + note?: Maybe<Scalars['String']> + /** A list of extra information that is added to the checkout. */ + customAttributes?: Maybe<Array<AttributeInput>> + /** + * Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + * The required attributes are city, province, and country. + * Full validation of the addresses is still done at complete time. + */ + allowPartialAddresses?: Maybe<Scalars['Boolean']> +} + +/** Return type for `checkoutAttributesUpdateV2` mutation. */ +export type CheckoutAttributesUpdateV2Payload = { + __typename?: 'CheckoutAttributesUpdateV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteFree` mutation. */ +export type CheckoutCompleteFreePayload = { + __typename?: 'CheckoutCompleteFreePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithCreditCard` mutation. */ +export type CheckoutCompleteWithCreditCardPayload = { + __typename?: 'CheckoutCompleteWithCreditCardPayload' + /** The checkout on which the payment was applied. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithCreditCardV2` mutation. */ +export type CheckoutCompleteWithCreditCardV2Payload = { + __typename?: 'CheckoutCompleteWithCreditCardV2Payload' + /** The checkout on which the payment was applied. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithTokenizedPayment` mutation. */ +export type CheckoutCompleteWithTokenizedPaymentPayload = { + __typename?: 'CheckoutCompleteWithTokenizedPaymentPayload' + /** The checkout on which the payment was applied. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithTokenizedPaymentV2` mutation. */ +export type CheckoutCompleteWithTokenizedPaymentV2Payload = { + __typename?: 'CheckoutCompleteWithTokenizedPaymentV2Payload' + /** The checkout on which the payment was applied. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCompleteWithTokenizedPaymentV3` mutation. */ +export type CheckoutCompleteWithTokenizedPaymentV3Payload = { + __typename?: 'CheckoutCompleteWithTokenizedPaymentV3Payload' + /** The checkout on which the payment was applied. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** A representation of the attempted payment. */ + payment?: Maybe<Payment> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to create a checkout. */ +export type CheckoutCreateInput = { + /** The email with which the customer wants to checkout. */ + email?: Maybe<Scalars['String']> + /** A list of line item objects, each one containing information about an item in the checkout. */ + lineItems?: Maybe<Array<CheckoutLineItemInput>> + /** The shipping address to where the line items will be shipped. */ + shippingAddress?: Maybe<MailingAddressInput> + /** The text of an optional note that a shop owner can attach to the checkout. */ + note?: Maybe<Scalars['String']> + /** A list of extra information that is added to the checkout. */ + customAttributes?: Maybe<Array<AttributeInput>> + /** + * Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + * The required attributes are city, province, and country. + * Full validation of addresses is still done at complete time. + */ + allowPartialAddresses?: Maybe<Scalars['Boolean']> + /** + * The three-letter currency code of one of the shop's enabled presentment currencies. + * Including this field creates a checkout in the specified currency. By default, new + * checkouts are created in the shop's primary currency. + */ + presentmentCurrencyCode?: Maybe<CurrencyCode> +} + +/** Return type for `checkoutCreate` mutation. */ +export type CheckoutCreatePayload = { + __typename?: 'CheckoutCreatePayload' + /** The new checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCustomerAssociate` mutation. */ +export type CheckoutCustomerAssociatePayload = { + __typename?: 'CheckoutCustomerAssociatePayload' + /** The updated checkout object. */ + checkout: Checkout + /** The associated customer object. */ + customer?: Maybe<Customer> + /** List of errors that occurred executing the mutation. */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCustomerAssociateV2` mutation. */ +export type CheckoutCustomerAssociateV2Payload = { + __typename?: 'CheckoutCustomerAssociateV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** The associated customer object. */ + customer?: Maybe<Customer> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCustomerDisassociate` mutation. */ +export type CheckoutCustomerDisassociatePayload = { + __typename?: 'CheckoutCustomerDisassociatePayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutCustomerDisassociateV2` mutation. */ +export type CheckoutCustomerDisassociateV2Payload = { + __typename?: 'CheckoutCustomerDisassociateV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutDiscountCodeApply` mutation. */ +export type CheckoutDiscountCodeApplyPayload = { + __typename?: 'CheckoutDiscountCodeApplyPayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutDiscountCodeApplyV2` mutation. */ +export type CheckoutDiscountCodeApplyV2Payload = { + __typename?: 'CheckoutDiscountCodeApplyV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutDiscountCodeRemove` mutation. */ +export type CheckoutDiscountCodeRemovePayload = { + __typename?: 'CheckoutDiscountCodeRemovePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutEmailUpdate` mutation. */ +export type CheckoutEmailUpdatePayload = { + __typename?: 'CheckoutEmailUpdatePayload' + /** The checkout object with the updated email. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutEmailUpdateV2` mutation. */ +export type CheckoutEmailUpdateV2Payload = { + __typename?: 'CheckoutEmailUpdateV2Payload' + /** The checkout object with the updated email. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Possible error codes that could be returned by CheckoutUserError. */ +export enum CheckoutErrorCode { + /** Input value is blank. */ + Blank = 'BLANK', + /** Input value is invalid. */ + Invalid = 'INVALID', + /** Input value is too long. */ + TooLong = 'TOO_LONG', + /** Input value is not present. */ + Present = 'PRESENT', + /** Input value should be less than maximum allowed value. */ + LessThan = 'LESS_THAN', + /** Input value should be greater than or equal to minimum allowed value. */ + GreaterThanOrEqualTo = 'GREATER_THAN_OR_EQUAL_TO', + /** Input value should be less or equal to maximum allowed value. */ + LessThanOrEqualTo = 'LESS_THAN_OR_EQUAL_TO', + /** Checkout is already completed. */ + AlreadyCompleted = 'ALREADY_COMPLETED', + /** Checkout is locked. */ + Locked = 'LOCKED', + /** Input value is not supported. */ + NotSupported = 'NOT_SUPPORTED', + /** Input email contains an invalid domain name. */ + BadDomain = 'BAD_DOMAIN', + /** Input Zip is invalid for country provided. */ + InvalidForCountry = 'INVALID_FOR_COUNTRY', + /** Input Zip is invalid for country and province provided. */ + InvalidForCountryAndProvince = 'INVALID_FOR_COUNTRY_AND_PROVINCE', + /** Invalid state in country. */ + InvalidStateInCountry = 'INVALID_STATE_IN_COUNTRY', + /** Invalid province in country. */ + InvalidProvinceInCountry = 'INVALID_PROVINCE_IN_COUNTRY', + /** Invalid region in country. */ + InvalidRegionInCountry = 'INVALID_REGION_IN_COUNTRY', + /** Shipping rate expired. */ + ShippingRateExpired = 'SHIPPING_RATE_EXPIRED', + /** Gift card cannot be applied to a checkout that contains a gift card. */ + GiftCardUnusable = 'GIFT_CARD_UNUSABLE', + /** Gift card is disabled. */ + GiftCardDisabled = 'GIFT_CARD_DISABLED', + /** Gift card code is invalid. */ + GiftCardCodeInvalid = 'GIFT_CARD_CODE_INVALID', + /** Gift card has already been applied. */ + GiftCardAlreadyApplied = 'GIFT_CARD_ALREADY_APPLIED', + /** Gift card currency does not match checkout currency. */ + GiftCardCurrencyMismatch = 'GIFT_CARD_CURRENCY_MISMATCH', + /** Gift card is expired. */ + GiftCardExpired = 'GIFT_CARD_EXPIRED', + /** Gift card has no funds left. */ + GiftCardDepleted = 'GIFT_CARD_DEPLETED', + /** Gift card was not found. */ + GiftCardNotFound = 'GIFT_CARD_NOT_FOUND', + /** Cart does not meet discount requirements notice. */ + CartDoesNotMeetDiscountRequirementsNotice = 'CART_DOES_NOT_MEET_DISCOUNT_REQUIREMENTS_NOTICE', + /** Discount expired. */ + DiscountExpired = 'DISCOUNT_EXPIRED', + /** Discount disabled. */ + DiscountDisabled = 'DISCOUNT_DISABLED', + /** Discount limit reached. */ + DiscountLimitReached = 'DISCOUNT_LIMIT_REACHED', + /** Discount not found. */ + DiscountNotFound = 'DISCOUNT_NOT_FOUND', + /** Customer already used once per customer discount notice. */ + CustomerAlreadyUsedOncePerCustomerDiscountNotice = 'CUSTOMER_ALREADY_USED_ONCE_PER_CUSTOMER_DISCOUNT_NOTICE', + /** Checkout is already completed. */ + Empty = 'EMPTY', + /** Not enough in stock. */ + NotEnoughInStock = 'NOT_ENOUGH_IN_STOCK', + /** Missing payment input. */ + MissingPaymentInput = 'MISSING_PAYMENT_INPUT', + /** The amount of the payment does not match the value to be paid. */ + TotalPriceMismatch = 'TOTAL_PRICE_MISMATCH', + /** Line item was not found in checkout. */ + LineItemNotFound = 'LINE_ITEM_NOT_FOUND', + /** Unable to apply discount. */ + UnableToApply = 'UNABLE_TO_APPLY', + /** Discount already applied. */ + DiscountAlreadyApplied = 'DISCOUNT_ALREADY_APPLIED', +} + +/** Return type for `checkoutGiftCardApply` mutation. */ +export type CheckoutGiftCardApplyPayload = { + __typename?: 'CheckoutGiftCardApplyPayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutGiftCardRemove` mutation. */ +export type CheckoutGiftCardRemovePayload = { + __typename?: 'CheckoutGiftCardRemovePayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutGiftCardRemoveV2` mutation. */ +export type CheckoutGiftCardRemoveV2Payload = { + __typename?: 'CheckoutGiftCardRemoveV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutGiftCardsAppend` mutation. */ +export type CheckoutGiftCardsAppendPayload = { + __typename?: 'CheckoutGiftCardsAppendPayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** A single line item in the checkout, grouped by variant and attributes. */ +export type CheckoutLineItem = Node & { + __typename?: 'CheckoutLineItem' + /** Extra information in the form of an array of Key-Value pairs about the line item. */ + customAttributes: Array<Attribute> + /** The discounts that have been allocated onto the checkout line item by discount applications. */ + discountAllocations: Array<DiscountAllocation> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The quantity of the line item. */ + quantity: Scalars['Int'] + /** Title of the line item. Defaults to the product's title. */ + title: Scalars['String'] + /** Unit price of the line item. */ + unitPrice?: Maybe<MoneyV2> + /** Product variant of the line item. */ + variant?: Maybe<ProductVariant> +} + +/** An auto-generated type for paginating through multiple CheckoutLineItems. */ +export type CheckoutLineItemConnection = { + __typename?: 'CheckoutLineItemConnection' + /** A list of edges. */ + edges: Array<CheckoutLineItemEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one CheckoutLineItem and a cursor during pagination. */ +export type CheckoutLineItemEdge = { + __typename?: 'CheckoutLineItemEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of CheckoutLineItemEdge. */ + node: CheckoutLineItem +} + +/** Specifies the input fields to create a line item on a checkout. */ +export type CheckoutLineItemInput = { + /** Extra information in the form of an array of Key-Value pairs about the line item. */ + customAttributes?: Maybe<Array<AttributeInput>> + /** The quantity of the line item. */ + quantity: Scalars['Int'] + /** The identifier of the product variant for the line item. */ + variantId: Scalars['ID'] +} + +/** Specifies the input fields to update a line item on the checkout. */ +export type CheckoutLineItemUpdateInput = { + /** The identifier of the line item. */ + id?: Maybe<Scalars['ID']> + /** The variant identifier of the line item. */ + variantId?: Maybe<Scalars['ID']> + /** The quantity of the line item. */ + quantity?: Maybe<Scalars['Int']> + /** Extra information in the form of an array of Key-Value pairs about the line item. */ + customAttributes?: Maybe<Array<AttributeInput>> +} + +/** Return type for `checkoutLineItemsAdd` mutation. */ +export type CheckoutLineItemsAddPayload = { + __typename?: 'CheckoutLineItemsAddPayload' + /** The updated checkout object. */ + items?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + // checkoutUserErrors: Array<CheckoutUserError> + // /** + // * List of errors that occurred executing the mutation. + // * @deprecated Use `checkoutUserErrors` instead + // */ + // userErrors: Array<UserError> +} + +/** Return type for `checkoutLineItemsRemove` mutation. */ +export type CheckoutLineItemsRemovePayload = { + __typename?: 'CheckoutLineItemsRemovePayload' + /** The updated checkout object. */ + items?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + // checkoutUserErrors: Array<CheckoutUserError> + // /** + // * List of errors that occurred executing the mutation. + // * @deprecated Use `checkoutUserErrors` instead + // */ + // userErrors: Array<UserError> +} + +/** Return type for `checkoutLineItemsReplace` mutation. */ +export type CheckoutLineItemsReplacePayload = { + __typename?: 'CheckoutLineItemsReplacePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + userErrors: Array<CheckoutUserError> +} + +/** Return type for `checkoutLineItemsUpdate` mutation. */ +export type CheckoutLineItemsUpdatePayload = { + __typename?: 'CheckoutLineItemsUpdatePayload' + /** The updated checkout object. */ + items?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + // checkoutUserErrors: Array<CheckoutUserError> + // /** + // * List of errors that occurred executing the mutation. + // * @deprecated Use `checkoutUserErrors` instead + // */ + // userErrors: Array<UserError> +} + +/** Return type for `checkoutShippingAddressUpdate` mutation. */ +export type CheckoutShippingAddressUpdatePayload = { + __typename?: 'CheckoutShippingAddressUpdatePayload' + /** The updated checkout object. */ + checkout: Checkout + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutShippingAddressUpdateV2` mutation. */ +export type CheckoutShippingAddressUpdateV2Payload = { + __typename?: 'CheckoutShippingAddressUpdateV2Payload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `checkoutShippingLineUpdate` mutation. */ +export type CheckoutShippingLineUpdatePayload = { + __typename?: 'CheckoutShippingLineUpdatePayload' + /** The updated checkout object. */ + checkout?: Maybe<Checkout> + /** List of errors that occurred executing the mutation. */ + checkoutUserErrors: Array<CheckoutUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `checkoutUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Represents an error that happens during execution of a checkout mutation. */ +export type CheckoutUserError = DisplayableError & { + __typename?: 'CheckoutUserError' + /** Error code to uniquely identify the error. */ + code?: Maybe<CheckoutErrorCode> + /** Path to the input field which caused the error. */ + field?: Maybe<Array<Scalars['String']>> + /** The error message. */ + message: Scalars['String'] +} + +/** A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. */ +export type Collection = Node & { + __typename?: 'Collection' + /** Stripped description of the collection, single line with HTML tags removed. */ + description: Scalars['String'] + /** The description of the collection, complete with HTML formatting. */ + descriptionHtml: Scalars['HTML'] + /** + * A human-friendly unique string for the collection automatically generated from its title. + * Limit of 255 characters. + */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** Image associated with the collection. */ + image?: Maybe<Image> + /** List of products in the collection. */ + products: ProductConnection + /** The collection’s name. Limit of 255 characters. */ + title: Scalars['String'] + /** The date and time when the collection was last modified. */ + updatedAt: Scalars['DateTime'] +} + +/** A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. */ +export type CollectionDescriptionArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. */ +export type CollectionImageArgs = { + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> +} + +/** A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. */ +export type CollectionProductsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductCollectionSortKeys> +} + +/** An auto-generated type for paginating through multiple Collections. */ +export type CollectionConnection = { + __typename?: 'CollectionConnection' + /** A list of edges. */ + edges: Array<CollectionEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Collection and a cursor during pagination. */ +export type CollectionEdge = { + __typename?: 'CollectionEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of CollectionEdge. */ + node: Collection +} + +/** The set of valid sort keys for the Collection query. */ +export enum CollectionSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `updated_at` value. */ + UpdatedAt = 'UPDATED_AT', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** A comment on an article. */ +export type Comment = Node & { + __typename?: 'Comment' + /** The comment’s author. */ + author: CommentAuthor + /** Stripped content of the comment, single line with HTML tags removed. */ + content: Scalars['String'] + /** The content of the comment, complete with HTML formatting. */ + contentHtml: Scalars['HTML'] + /** Globally unique identifier. */ + id: Scalars['ID'] +} + +/** A comment on an article. */ +export type CommentContentArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** The author of a comment. */ +export type CommentAuthor = { + __typename?: 'CommentAuthor' + /** The author's email. */ + email: Scalars['String'] + /** The author’s name. */ + name: Scalars['String'] +} + +/** An auto-generated type for paginating through multiple Comments. */ +export type CommentConnection = { + __typename?: 'CommentConnection' + /** A list of edges. */ + edges: Array<CommentEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Comment and a cursor during pagination. */ +export type CommentEdge = { + __typename?: 'CommentEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of CommentEdge. */ + node: Comment +} + +/** ISO 3166-1 alpha-2 country codes with some differences. */ +export enum CountryCode { + /** Afghanistan. */ + Af = 'AF', + /** Åland Islands. */ + Ax = 'AX', + /** Albania. */ + Al = 'AL', + /** Algeria. */ + Dz = 'DZ', + /** Andorra. */ + Ad = 'AD', + /** Angola. */ + Ao = 'AO', + /** Anguilla. */ + Ai = 'AI', + /** Antigua & Barbuda. */ + Ag = 'AG', + /** Argentina. */ + Ar = 'AR', + /** Armenia. */ + Am = 'AM', + /** Aruba. */ + Aw = 'AW', + /** Australia. */ + Au = 'AU', + /** Austria. */ + At = 'AT', + /** Azerbaijan. */ + Az = 'AZ', + /** Bahamas. */ + Bs = 'BS', + /** Bahrain. */ + Bh = 'BH', + /** Bangladesh. */ + Bd = 'BD', + /** Barbados. */ + Bb = 'BB', + /** Belarus. */ + By = 'BY', + /** Belgium. */ + Be = 'BE', + /** Belize. */ + Bz = 'BZ', + /** Benin. */ + Bj = 'BJ', + /** Bermuda. */ + Bm = 'BM', + /** Bhutan. */ + Bt = 'BT', + /** Bolivia. */ + Bo = 'BO', + /** Bosnia & Herzegovina. */ + Ba = 'BA', + /** Botswana. */ + Bw = 'BW', + /** Bouvet Island. */ + Bv = 'BV', + /** Brazil. */ + Br = 'BR', + /** British Indian Ocean Territory. */ + Io = 'IO', + /** Brunei. */ + Bn = 'BN', + /** Bulgaria. */ + Bg = 'BG', + /** Burkina Faso. */ + Bf = 'BF', + /** Burundi. */ + Bi = 'BI', + /** Cambodia. */ + Kh = 'KH', + /** Canada. */ + Ca = 'CA', + /** Cape Verde. */ + Cv = 'CV', + /** Caribbean Netherlands. */ + Bq = 'BQ', + /** Cayman Islands. */ + Ky = 'KY', + /** Central African Republic. */ + Cf = 'CF', + /** Chad. */ + Td = 'TD', + /** Chile. */ + Cl = 'CL', + /** China. */ + Cn = 'CN', + /** Christmas Island. */ + Cx = 'CX', + /** Cocos (Keeling) Islands. */ + Cc = 'CC', + /** Colombia. */ + Co = 'CO', + /** Comoros. */ + Km = 'KM', + /** Congo - Brazzaville. */ + Cg = 'CG', + /** Congo - Kinshasa. */ + Cd = 'CD', + /** Cook Islands. */ + Ck = 'CK', + /** Costa Rica. */ + Cr = 'CR', + /** Croatia. */ + Hr = 'HR', + /** Cuba. */ + Cu = 'CU', + /** Curaçao. */ + Cw = 'CW', + /** Cyprus. */ + Cy = 'CY', + /** Czechia. */ + Cz = 'CZ', + /** Côte d’Ivoire. */ + Ci = 'CI', + /** Denmark. */ + Dk = 'DK', + /** Djibouti. */ + Dj = 'DJ', + /** Dominica. */ + Dm = 'DM', + /** Dominican Republic. */ + Do = 'DO', + /** Ecuador. */ + Ec = 'EC', + /** Egypt. */ + Eg = 'EG', + /** El Salvador. */ + Sv = 'SV', + /** Equatorial Guinea. */ + Gq = 'GQ', + /** Eritrea. */ + Er = 'ER', + /** Estonia. */ + Ee = 'EE', + /** Eswatini. */ + Sz = 'SZ', + /** Ethiopia. */ + Et = 'ET', + /** Falkland Islands. */ + Fk = 'FK', + /** Faroe Islands. */ + Fo = 'FO', + /** Fiji. */ + Fj = 'FJ', + /** Finland. */ + Fi = 'FI', + /** France. */ + Fr = 'FR', + /** French Guiana. */ + Gf = 'GF', + /** French Polynesia. */ + Pf = 'PF', + /** French Southern Territories. */ + Tf = 'TF', + /** Gabon. */ + Ga = 'GA', + /** Gambia. */ + Gm = 'GM', + /** Georgia. */ + Ge = 'GE', + /** Germany. */ + De = 'DE', + /** Ghana. */ + Gh = 'GH', + /** Gibraltar. */ + Gi = 'GI', + /** Greece. */ + Gr = 'GR', + /** Greenland. */ + Gl = 'GL', + /** Grenada. */ + Gd = 'GD', + /** Guadeloupe. */ + Gp = 'GP', + /** Guatemala. */ + Gt = 'GT', + /** Guernsey. */ + Gg = 'GG', + /** Guinea. */ + Gn = 'GN', + /** Guinea-Bissau. */ + Gw = 'GW', + /** Guyana. */ + Gy = 'GY', + /** Haiti. */ + Ht = 'HT', + /** Heard & McDonald Islands. */ + Hm = 'HM', + /** Vatican City. */ + Va = 'VA', + /** Honduras. */ + Hn = 'HN', + /** Hong Kong SAR. */ + Hk = 'HK', + /** Hungary. */ + Hu = 'HU', + /** Iceland. */ + Is = 'IS', + /** India. */ + In = 'IN', + /** Indonesia. */ + Id = 'ID', + /** Iran. */ + Ir = 'IR', + /** Iraq. */ + Iq = 'IQ', + /** Ireland. */ + Ie = 'IE', + /** Isle of Man. */ + Im = 'IM', + /** Israel. */ + Il = 'IL', + /** Italy. */ + It = 'IT', + /** Jamaica. */ + Jm = 'JM', + /** Japan. */ + Jp = 'JP', + /** Jersey. */ + Je = 'JE', + /** Jordan. */ + Jo = 'JO', + /** Kazakhstan. */ + Kz = 'KZ', + /** Kenya. */ + Ke = 'KE', + /** Kiribati. */ + Ki = 'KI', + /** North Korea. */ + Kp = 'KP', + /** Kosovo. */ + Xk = 'XK', + /** Kuwait. */ + Kw = 'KW', + /** Kyrgyzstan. */ + Kg = 'KG', + /** Laos. */ + La = 'LA', + /** Latvia. */ + Lv = 'LV', + /** Lebanon. */ + Lb = 'LB', + /** Lesotho. */ + Ls = 'LS', + /** Liberia. */ + Lr = 'LR', + /** Libya. */ + Ly = 'LY', + /** Liechtenstein. */ + Li = 'LI', + /** Lithuania. */ + Lt = 'LT', + /** Luxembourg. */ + Lu = 'LU', + /** Macao SAR. */ + Mo = 'MO', + /** Madagascar. */ + Mg = 'MG', + /** Malawi. */ + Mw = 'MW', + /** Malaysia. */ + My = 'MY', + /** Maldives. */ + Mv = 'MV', + /** Mali. */ + Ml = 'ML', + /** Malta. */ + Mt = 'MT', + /** Martinique. */ + Mq = 'MQ', + /** Mauritania. */ + Mr = 'MR', + /** Mauritius. */ + Mu = 'MU', + /** Mayotte. */ + Yt = 'YT', + /** Mexico. */ + Mx = 'MX', + /** Moldova. */ + Md = 'MD', + /** Monaco. */ + Mc = 'MC', + /** Mongolia. */ + Mn = 'MN', + /** Montenegro. */ + Me = 'ME', + /** Montserrat. */ + Ms = 'MS', + /** Morocco. */ + Ma = 'MA', + /** Mozambique. */ + Mz = 'MZ', + /** Myanmar (Burma). */ + Mm = 'MM', + /** Namibia. */ + Na = 'NA', + /** Nauru. */ + Nr = 'NR', + /** Nepal. */ + Np = 'NP', + /** Netherlands. */ + Nl = 'NL', + /** Netherlands Antilles. */ + An = 'AN', + /** New Caledonia. */ + Nc = 'NC', + /** New Zealand. */ + Nz = 'NZ', + /** Nicaragua. */ + Ni = 'NI', + /** Niger. */ + Ne = 'NE', + /** Nigeria. */ + Ng = 'NG', + /** Niue. */ + Nu = 'NU', + /** Norfolk Island. */ + Nf = 'NF', + /** North Macedonia. */ + Mk = 'MK', + /** Norway. */ + No = 'NO', + /** Oman. */ + Om = 'OM', + /** Pakistan. */ + Pk = 'PK', + /** Palestinian Territories. */ + Ps = 'PS', + /** Panama. */ + Pa = 'PA', + /** Papua New Guinea. */ + Pg = 'PG', + /** Paraguay. */ + Py = 'PY', + /** Peru. */ + Pe = 'PE', + /** Philippines. */ + Ph = 'PH', + /** Pitcairn Islands. */ + Pn = 'PN', + /** Poland. */ + Pl = 'PL', + /** Portugal. */ + Pt = 'PT', + /** Qatar. */ + Qa = 'QA', + /** Cameroon. */ + Cm = 'CM', + /** Réunion. */ + Re = 'RE', + /** Romania. */ + Ro = 'RO', + /** Russia. */ + Ru = 'RU', + /** Rwanda. */ + Rw = 'RW', + /** St. Barthélemy. */ + Bl = 'BL', + /** St. Helena. */ + Sh = 'SH', + /** St. Kitts & Nevis. */ + Kn = 'KN', + /** St. Lucia. */ + Lc = 'LC', + /** St. Martin. */ + Mf = 'MF', + /** St. Pierre & Miquelon. */ + Pm = 'PM', + /** Samoa. */ + Ws = 'WS', + /** San Marino. */ + Sm = 'SM', + /** São Tomé & Príncipe. */ + St = 'ST', + /** Saudi Arabia. */ + Sa = 'SA', + /** Senegal. */ + Sn = 'SN', + /** Serbia. */ + Rs = 'RS', + /** Seychelles. */ + Sc = 'SC', + /** Sierra Leone. */ + Sl = 'SL', + /** Singapore. */ + Sg = 'SG', + /** Sint Maarten. */ + Sx = 'SX', + /** Slovakia. */ + Sk = 'SK', + /** Slovenia. */ + Si = 'SI', + /** Solomon Islands. */ + Sb = 'SB', + /** Somalia. */ + So = 'SO', + /** South Africa. */ + Za = 'ZA', + /** South Georgia & South Sandwich Islands. */ + Gs = 'GS', + /** South Korea. */ + Kr = 'KR', + /** South Sudan. */ + Ss = 'SS', + /** Spain. */ + Es = 'ES', + /** Sri Lanka. */ + Lk = 'LK', + /** St. Vincent & Grenadines. */ + Vc = 'VC', + /** Sudan. */ + Sd = 'SD', + /** Suriname. */ + Sr = 'SR', + /** Svalbard & Jan Mayen. */ + Sj = 'SJ', + /** Sweden. */ + Se = 'SE', + /** Switzerland. */ + Ch = 'CH', + /** Syria. */ + Sy = 'SY', + /** Taiwan. */ + Tw = 'TW', + /** Tajikistan. */ + Tj = 'TJ', + /** Tanzania. */ + Tz = 'TZ', + /** Thailand. */ + Th = 'TH', + /** Timor-Leste. */ + Tl = 'TL', + /** Togo. */ + Tg = 'TG', + /** Tokelau. */ + Tk = 'TK', + /** Tonga. */ + To = 'TO', + /** Trinidad & Tobago. */ + Tt = 'TT', + /** Tunisia. */ + Tn = 'TN', + /** Turkey. */ + Tr = 'TR', + /** Turkmenistan. */ + Tm = 'TM', + /** Turks & Caicos Islands. */ + Tc = 'TC', + /** Tuvalu. */ + Tv = 'TV', + /** Uganda. */ + Ug = 'UG', + /** Ukraine. */ + Ua = 'UA', + /** United Arab Emirates. */ + Ae = 'AE', + /** United Kingdom. */ + Gb = 'GB', + /** United States. */ + Us = 'US', + /** U.S. Outlying Islands. */ + Um = 'UM', + /** Uruguay. */ + Uy = 'UY', + /** Uzbekistan. */ + Uz = 'UZ', + /** Vanuatu. */ + Vu = 'VU', + /** Venezuela. */ + Ve = 'VE', + /** Vietnam. */ + Vn = 'VN', + /** British Virgin Islands. */ + Vg = 'VG', + /** Wallis & Futuna. */ + Wf = 'WF', + /** Western Sahara. */ + Eh = 'EH', + /** Yemen. */ + Ye = 'YE', + /** Zambia. */ + Zm = 'ZM', + /** Zimbabwe. */ + Zw = 'ZW', +} + +/** Credit card information used for a payment. */ +export type CreditCard = { + __typename?: 'CreditCard' + /** The brand of the credit card. */ + brand?: Maybe<Scalars['String']> + /** The expiry month of the credit card. */ + expiryMonth?: Maybe<Scalars['Int']> + /** The expiry year of the credit card. */ + expiryYear?: Maybe<Scalars['Int']> + /** The credit card's BIN number. */ + firstDigits?: Maybe<Scalars['String']> + /** The first name of the card holder. */ + firstName?: Maybe<Scalars['String']> + /** The last 4 digits of the credit card. */ + lastDigits?: Maybe<Scalars['String']> + /** The last name of the card holder. */ + lastName?: Maybe<Scalars['String']> + /** The masked credit card number with only the last 4 digits displayed. */ + maskedNumber?: Maybe<Scalars['String']> +} + +/** + * Specifies the fields required to complete a checkout with + * a Shopify vaulted credit card payment. + */ +export type CreditCardPaymentInput = { + /** The amount of the payment. */ + amount: Scalars['Money'] + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** The ID returned by Shopify's Card Vault. */ + vaultId: Scalars['String'] + /** Executes the payment in test mode if possible. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> +} + +/** + * Specifies the fields required to complete a checkout with + * a Shopify vaulted credit card payment. + */ +export type CreditCardPaymentInputV2 = { + /** The amount and currency of the payment. */ + paymentAmount: MoneyInput + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** The ID returned by Shopify's Card Vault. */ + vaultId: Scalars['String'] + /** Executes the payment in test mode if possible. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> +} + +/** The part of the image that should remain after cropping. */ +export enum CropRegion { + /** Keep the center of the image. */ + Center = 'CENTER', + /** Keep the top of the image. */ + Top = 'TOP', + /** Keep the bottom of the image. */ + Bottom = 'BOTTOM', + /** Keep the left of the image. */ + Left = 'LEFT', + /** Keep the right of the image. */ + Right = 'RIGHT', +} + +/** Currency codes. */ +export enum CurrencyCode { + /** United States Dollars (USD). */ + Usd = 'USD', + /** Euro (EUR). */ + Eur = 'EUR', + /** United Kingdom Pounds (GBP). */ + Gbp = 'GBP', + /** Canadian Dollars (CAD). */ + Cad = 'CAD', + /** Afghan Afghani (AFN). */ + Afn = 'AFN', + /** Albanian Lek (ALL). */ + All = 'ALL', + /** Algerian Dinar (DZD). */ + Dzd = 'DZD', + /** Angolan Kwanza (AOA). */ + Aoa = 'AOA', + /** Argentine Pesos (ARS). */ + Ars = 'ARS', + /** Armenian Dram (AMD). */ + Amd = 'AMD', + /** Aruban Florin (AWG). */ + Awg = 'AWG', + /** Australian Dollars (AUD). */ + Aud = 'AUD', + /** Barbadian Dollar (BBD). */ + Bbd = 'BBD', + /** Azerbaijani Manat (AZN). */ + Azn = 'AZN', + /** Bangladesh Taka (BDT). */ + Bdt = 'BDT', + /** Bahamian Dollar (BSD). */ + Bsd = 'BSD', + /** Bahraini Dinar (BHD). */ + Bhd = 'BHD', + /** Burundian Franc (BIF). */ + Bif = 'BIF', + /** Belarusian Ruble (BYN). */ + Byn = 'BYN', + /** Belarusian Ruble (BYR). */ + Byr = 'BYR', + /** Belize Dollar (BZD). */ + Bzd = 'BZD', + /** Bermudian Dollar (BMD). */ + Bmd = 'BMD', + /** Bhutanese Ngultrum (BTN). */ + Btn = 'BTN', + /** Bosnia and Herzegovina Convertible Mark (BAM). */ + Bam = 'BAM', + /** Brazilian Real (BRL). */ + Brl = 'BRL', + /** Bolivian Boliviano (BOB). */ + Bob = 'BOB', + /** Botswana Pula (BWP). */ + Bwp = 'BWP', + /** Brunei Dollar (BND). */ + Bnd = 'BND', + /** Bulgarian Lev (BGN). */ + Bgn = 'BGN', + /** Burmese Kyat (MMK). */ + Mmk = 'MMK', + /** Cambodian Riel. */ + Khr = 'KHR', + /** Cape Verdean escudo (CVE). */ + Cve = 'CVE', + /** Cayman Dollars (KYD). */ + Kyd = 'KYD', + /** Central African CFA Franc (XAF). */ + Xaf = 'XAF', + /** Chilean Peso (CLP). */ + Clp = 'CLP', + /** Chinese Yuan Renminbi (CNY). */ + Cny = 'CNY', + /** Colombian Peso (COP). */ + Cop = 'COP', + /** Comorian Franc (KMF). */ + Kmf = 'KMF', + /** Congolese franc (CDF). */ + Cdf = 'CDF', + /** Costa Rican Colones (CRC). */ + Crc = 'CRC', + /** Croatian Kuna (HRK). */ + Hrk = 'HRK', + /** Czech Koruny (CZK). */ + Czk = 'CZK', + /** Danish Kroner (DKK). */ + Dkk = 'DKK', + /** Djiboutian Franc (DJF). */ + Djf = 'DJF', + /** Dominican Peso (DOP). */ + Dop = 'DOP', + /** East Caribbean Dollar (XCD). */ + Xcd = 'XCD', + /** Egyptian Pound (EGP). */ + Egp = 'EGP', + /** Eritrean Nakfa (ERN). */ + Ern = 'ERN', + /** Ethiopian Birr (ETB). */ + Etb = 'ETB', + /** Falkland Islands Pounds (FKP). */ + Fkp = 'FKP', + /** CFP Franc (XPF). */ + Xpf = 'XPF', + /** Fijian Dollars (FJD). */ + Fjd = 'FJD', + /** Gibraltar Pounds (GIP). */ + Gip = 'GIP', + /** Gambian Dalasi (GMD). */ + Gmd = 'GMD', + /** Ghanaian Cedi (GHS). */ + Ghs = 'GHS', + /** Guatemalan Quetzal (GTQ). */ + Gtq = 'GTQ', + /** Guyanese Dollar (GYD). */ + Gyd = 'GYD', + /** Georgian Lari (GEL). */ + Gel = 'GEL', + /** Guinean Franc (GNF). */ + Gnf = 'GNF', + /** Haitian Gourde (HTG). */ + Htg = 'HTG', + /** Honduran Lempira (HNL). */ + Hnl = 'HNL', + /** Hong Kong Dollars (HKD). */ + Hkd = 'HKD', + /** Hungarian Forint (HUF). */ + Huf = 'HUF', + /** Icelandic Kronur (ISK). */ + Isk = 'ISK', + /** Indian Rupees (INR). */ + Inr = 'INR', + /** Indonesian Rupiah (IDR). */ + Idr = 'IDR', + /** Israeli New Shekel (NIS). */ + Ils = 'ILS', + /** Iranian Rial (IRR). */ + Irr = 'IRR', + /** Iraqi Dinar (IQD). */ + Iqd = 'IQD', + /** Jamaican Dollars (JMD). */ + Jmd = 'JMD', + /** Japanese Yen (JPY). */ + Jpy = 'JPY', + /** Jersey Pound. */ + Jep = 'JEP', + /** Jordanian Dinar (JOD). */ + Jod = 'JOD', + /** Kazakhstani Tenge (KZT). */ + Kzt = 'KZT', + /** Kenyan Shilling (KES). */ + Kes = 'KES', + /** Kiribati Dollar (KID). */ + Kid = 'KID', + /** Kuwaiti Dinar (KWD). */ + Kwd = 'KWD', + /** Kyrgyzstani Som (KGS). */ + Kgs = 'KGS', + /** Laotian Kip (LAK). */ + Lak = 'LAK', + /** Latvian Lati (LVL). */ + Lvl = 'LVL', + /** Lebanese Pounds (LBP). */ + Lbp = 'LBP', + /** Lesotho Loti (LSL). */ + Lsl = 'LSL', + /** Liberian Dollar (LRD). */ + Lrd = 'LRD', + /** Libyan Dinar (LYD). */ + Lyd = 'LYD', + /** Lithuanian Litai (LTL). */ + Ltl = 'LTL', + /** Malagasy Ariary (MGA). */ + Mga = 'MGA', + /** Macedonia Denar (MKD). */ + Mkd = 'MKD', + /** Macanese Pataca (MOP). */ + Mop = 'MOP', + /** Malawian Kwacha (MWK). */ + Mwk = 'MWK', + /** Maldivian Rufiyaa (MVR). */ + Mvr = 'MVR', + /** Mauritanian Ouguiya (MRU). */ + Mru = 'MRU', + /** Mexican Pesos (MXN). */ + Mxn = 'MXN', + /** Malaysian Ringgits (MYR). */ + Myr = 'MYR', + /** Mauritian Rupee (MUR). */ + Mur = 'MUR', + /** Moldovan Leu (MDL). */ + Mdl = 'MDL', + /** Moroccan Dirham. */ + Mad = 'MAD', + /** Mongolian Tugrik. */ + Mnt = 'MNT', + /** Mozambican Metical. */ + Mzn = 'MZN', + /** Namibian Dollar. */ + Nad = 'NAD', + /** Nepalese Rupee (NPR). */ + Npr = 'NPR', + /** Netherlands Antillean Guilder. */ + Ang = 'ANG', + /** New Zealand Dollars (NZD). */ + Nzd = 'NZD', + /** Nicaraguan Córdoba (NIO). */ + Nio = 'NIO', + /** Nigerian Naira (NGN). */ + Ngn = 'NGN', + /** Norwegian Kroner (NOK). */ + Nok = 'NOK', + /** Omani Rial (OMR). */ + Omr = 'OMR', + /** Panamian Balboa (PAB). */ + Pab = 'PAB', + /** Pakistani Rupee (PKR). */ + Pkr = 'PKR', + /** Papua New Guinean Kina (PGK). */ + Pgk = 'PGK', + /** Paraguayan Guarani (PYG). */ + Pyg = 'PYG', + /** Peruvian Nuevo Sol (PEN). */ + Pen = 'PEN', + /** Philippine Peso (PHP). */ + Php = 'PHP', + /** Polish Zlotych (PLN). */ + Pln = 'PLN', + /** Qatari Rial (QAR). */ + Qar = 'QAR', + /** Romanian Lei (RON). */ + Ron = 'RON', + /** Russian Rubles (RUB). */ + Rub = 'RUB', + /** Rwandan Franc (RWF). */ + Rwf = 'RWF', + /** Samoan Tala (WST). */ + Wst = 'WST', + /** Saint Helena Pounds (SHP). */ + Shp = 'SHP', + /** Saudi Riyal (SAR). */ + Sar = 'SAR', + /** Sao Tome And Principe Dobra (STD). */ + Std = 'STD', + /** Serbian dinar (RSD). */ + Rsd = 'RSD', + /** Seychellois Rupee (SCR). */ + Scr = 'SCR', + /** Sierra Leonean Leone (SLL). */ + Sll = 'SLL', + /** Singapore Dollars (SGD). */ + Sgd = 'SGD', + /** Sudanese Pound (SDG). */ + Sdg = 'SDG', + /** Somali Shilling (SOS). */ + Sos = 'SOS', + /** Syrian Pound (SYP). */ + Syp = 'SYP', + /** South African Rand (ZAR). */ + Zar = 'ZAR', + /** South Korean Won (KRW). */ + Krw = 'KRW', + /** South Sudanese Pound (SSP). */ + Ssp = 'SSP', + /** Solomon Islands Dollar (SBD). */ + Sbd = 'SBD', + /** Sri Lankan Rupees (LKR). */ + Lkr = 'LKR', + /** Surinamese Dollar (SRD). */ + Srd = 'SRD', + /** Swazi Lilangeni (SZL). */ + Szl = 'SZL', + /** Swedish Kronor (SEK). */ + Sek = 'SEK', + /** Swiss Francs (CHF). */ + Chf = 'CHF', + /** Taiwan Dollars (TWD). */ + Twd = 'TWD', + /** Thai baht (THB). */ + Thb = 'THB', + /** Tajikistani Somoni (TJS). */ + Tjs = 'TJS', + /** Tanzanian Shilling (TZS). */ + Tzs = 'TZS', + /** Tongan Pa'anga (TOP). */ + Top = 'TOP', + /** Trinidad and Tobago Dollars (TTD). */ + Ttd = 'TTD', + /** Tunisian Dinar (TND). */ + Tnd = 'TND', + /** Turkish Lira (TRY). */ + Try = 'TRY', + /** Turkmenistani Manat (TMT). */ + Tmt = 'TMT', + /** Ugandan Shilling (UGX). */ + Ugx = 'UGX', + /** Ukrainian Hryvnia (UAH). */ + Uah = 'UAH', + /** United Arab Emirates Dirham (AED). */ + Aed = 'AED', + /** Uruguayan Pesos (UYU). */ + Uyu = 'UYU', + /** Uzbekistan som (UZS). */ + Uzs = 'UZS', + /** Vanuatu Vatu (VUV). */ + Vuv = 'VUV', + /** Venezuelan Bolivares (VEF). */ + Vef = 'VEF', + /** Venezuelan Bolivares (VES). */ + Ves = 'VES', + /** Vietnamese đồng (VND). */ + Vnd = 'VND', + /** West African CFA franc (XOF). */ + Xof = 'XOF', + /** Yemeni Rial (YER). */ + Yer = 'YER', + /** Zambian Kwacha (ZMW). */ + Zmw = 'ZMW', +} + +/** A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. */ +export type Customer = { + __typename?: 'Customer' + /** Indicates whether the customer has consented to be sent marketing material via email. */ + acceptsMarketing: Scalars['Boolean'] + /** A list of addresses for the customer. */ + addresses: MailingAddressConnection + /** The date and time when the customer was created. */ + createdAt: Scalars['DateTime'] + /** The customer’s default address. */ + defaultAddress?: Maybe<MailingAddress> + /** The customer’s name, email or phone number. */ + displayName: Scalars['String'] + /** The customer’s email address. */ + email?: Maybe<Scalars['String']> + /** The customer’s first name. */ + firstName?: Maybe<Scalars['String']> + /** A unique identifier for the customer. */ + id: Scalars['ID'] + /** The customer's most recently updated, incomplete checkout. */ + lastIncompleteCheckout?: Maybe<Checkout> + /** The customer’s last name. */ + lastName?: Maybe<Scalars['String']> + /** The orders associated with the customer. */ + orders: OrderConnection + /** The customer’s phone number. */ + phone?: Maybe<Scalars['String']> + /** + * A comma separated list of tags that have been added to the customer. + * Additional access scope required: unauthenticated_read_customer_tags. + */ + tags: Array<Scalars['String']> + /** The date and time when the customer information was updated. */ + updatedAt: Scalars['DateTime'] +} + +/** A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. */ +export type CustomerAddressesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. */ +export type CustomerOrdersArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<OrderSortKeys> + query?: Maybe<Scalars['String']> +} + +/** A CustomerAccessToken represents the unique token required to make modifications to the customer object. */ +export type CustomerAccessToken = { + __typename?: 'CustomerAccessToken' + /** The customer’s access token. */ + accessToken: Scalars['String'] + /** The date and time when the customer access token expires. */ + expiresAt: Scalars['DateTime'] +} + +/** Specifies the input fields required to create a customer access token. */ +export type CustomerAccessTokenCreateInput = { + /** The email associated to the customer. */ + email: Scalars['String'] + /** The login password to be used by the customer. */ + password: Scalars['String'] +} + +/** Return type for `customerAccessTokenCreate` mutation. */ +export type CustomerAccessTokenCreatePayload = { + __typename?: 'CustomerAccessTokenCreatePayload' + /** The newly created customer access token object. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerAccessTokenCreateWithMultipass` mutation. */ +export type CustomerAccessTokenCreateWithMultipassPayload = { + __typename?: 'CustomerAccessTokenCreateWithMultipassPayload' + /** An access token object associated with the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> +} + +/** Return type for `customerAccessTokenDelete` mutation. */ +export type CustomerAccessTokenDeletePayload = { + __typename?: 'CustomerAccessTokenDeletePayload' + /** The destroyed access token. */ + deletedAccessToken?: Maybe<Scalars['String']> + /** ID of the destroyed customer access token. */ + deletedCustomerAccessTokenId?: Maybe<Scalars['String']> + /** List of errors that occurred executing the mutation. */ + userErrors: Array<UserError> +} + +/** Return type for `customerAccessTokenRenew` mutation. */ +export type CustomerAccessTokenRenewPayload = { + __typename?: 'CustomerAccessTokenRenewPayload' + /** The renewed customer access token object. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + userErrors: Array<UserError> +} + +/** Return type for `customerActivateByUrl` mutation. */ +export type CustomerActivateByUrlPayload = { + __typename?: 'CustomerActivateByUrlPayload' + /** The customer that was activated. */ + customer?: Maybe<Customer> + /** A new customer access token for the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> +} + +/** Specifies the input fields required to activate a customer. */ +export type CustomerActivateInput = { + /** The activation token required to activate the customer. */ + activationToken: Scalars['String'] + /** New password that will be set during activation. */ + password: Scalars['String'] +} + +/** Return type for `customerActivate` mutation. */ +export type CustomerActivatePayload = { + __typename?: 'CustomerActivatePayload' + /** The customer object. */ + customer?: Maybe<Customer> + /** A newly created customer access token object for the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerAddressCreate` mutation. */ +export type CustomerAddressCreatePayload = { + __typename?: 'CustomerAddressCreatePayload' + /** The new customer address object. */ + customerAddress?: Maybe<MailingAddress> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerAddressDelete` mutation. */ +export type CustomerAddressDeletePayload = { + __typename?: 'CustomerAddressDeletePayload' + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** ID of the deleted customer address. */ + deletedCustomerAddressId?: Maybe<Scalars['String']> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerAddressUpdate` mutation. */ +export type CustomerAddressUpdatePayload = { + __typename?: 'CustomerAddressUpdatePayload' + /** The customer’s updated mailing address. */ + customerAddress?: Maybe<MailingAddress> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to create a new customer. */ +export type CustomerCreateInput = { + /** The customer’s first name. */ + firstName?: Maybe<Scalars['String']> + /** The customer’s last name. */ + lastName?: Maybe<Scalars['String']> + /** The customer’s email. */ + email: Scalars['String'] + /** + * A unique phone number for the customer. + * + * Formatted using E.164 standard. For example, _+16135551111_. + */ + phone?: Maybe<Scalars['String']> + /** The login password used by the customer. */ + password: Scalars['String'] + /** Indicates whether the customer has consented to be sent marketing material via email. */ + acceptsMarketing?: Maybe<Scalars['Boolean']> +} + +/** Return type for `customerCreate` mutation. */ +export type CustomerCreatePayload = { + __typename?: 'CustomerCreatePayload' + /** The created customer object. */ + customer?: Maybe<Customer> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerDefaultAddressUpdate` mutation. */ +export type CustomerDefaultAddressUpdatePayload = { + __typename?: 'CustomerDefaultAddressUpdatePayload' + /** The updated customer object. */ + customer?: Maybe<Customer> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Possible error codes that could be returned by CustomerUserError. */ +export enum CustomerErrorCode { + /** Input value is blank. */ + Blank = 'BLANK', + /** Input value is invalid. */ + Invalid = 'INVALID', + /** Input value is already taken. */ + Taken = 'TAKEN', + /** Input value is too long. */ + TooLong = 'TOO_LONG', + /** Input value is too short. */ + TooShort = 'TOO_SHORT', + /** Unidentified customer. */ + UnidentifiedCustomer = 'UNIDENTIFIED_CUSTOMER', + /** Customer is disabled. */ + CustomerDisabled = 'CUSTOMER_DISABLED', + /** Input password starts or ends with whitespace. */ + PasswordStartsOrEndsWithWhitespace = 'PASSWORD_STARTS_OR_ENDS_WITH_WHITESPACE', + /** Input contains HTML tags. */ + ContainsHtmlTags = 'CONTAINS_HTML_TAGS', + /** Input contains URL. */ + ContainsUrl = 'CONTAINS_URL', + /** Invalid activation token. */ + TokenInvalid = 'TOKEN_INVALID', + /** Customer already enabled. */ + AlreadyEnabled = 'ALREADY_ENABLED', + /** Address does not exist. */ + NotFound = 'NOT_FOUND', + /** Input email contains an invalid domain name. */ + BadDomain = 'BAD_DOMAIN', + /** Multipass token is not valid. */ + InvalidMultipassRequest = 'INVALID_MULTIPASS_REQUEST', +} + +/** Return type for `customerRecover` mutation. */ +export type CustomerRecoverPayload = { + __typename?: 'CustomerRecoverPayload' + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Return type for `customerResetByUrl` mutation. */ +export type CustomerResetByUrlPayload = { + __typename?: 'CustomerResetByUrlPayload' + /** The customer object which was reset. */ + customer?: Maybe<Customer> + /** A newly created customer access token object for the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to reset a customer’s password. */ +export type CustomerResetInput = { + /** The reset token required to reset the customer’s password. */ + resetToken: Scalars['String'] + /** New password that will be set as part of the reset password process. */ + password: Scalars['String'] +} + +/** Return type for `customerReset` mutation. */ +export type CustomerResetPayload = { + __typename?: 'CustomerResetPayload' + /** The customer object which was reset. */ + customer?: Maybe<Customer> + /** A newly created customer access token object for the customer. */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Specifies the fields required to update the Customer information. */ +export type CustomerUpdateInput = { + /** The customer’s first name. */ + firstName?: Maybe<Scalars['String']> + /** The customer’s last name. */ + lastName?: Maybe<Scalars['String']> + /** The customer’s email. */ + email?: Maybe<Scalars['String']> + /** + * A unique phone number for the customer. + * + * Formatted using E.164 standard. For example, _+16135551111_. To remove the phone number, specify `null`. + */ + phone?: Maybe<Scalars['String']> + /** The login password used by the customer. */ + password?: Maybe<Scalars['String']> + /** Indicates whether the customer has consented to be sent marketing material via email. */ + acceptsMarketing?: Maybe<Scalars['Boolean']> +} + +/** Return type for `customerUpdate` mutation. */ +export type CustomerUpdatePayload = { + __typename?: 'CustomerUpdatePayload' + /** The updated customer object. */ + customer?: Maybe<Customer> + /** + * The newly created customer access token. If the customer's password is updated, all previous access tokens + * (including the one used to perform this mutation) become invalid, and a new token is generated. + */ + customerAccessToken?: Maybe<CustomerAccessToken> + /** List of errors that occurred executing the mutation. */ + customerUserErrors: Array<CustomerUserError> + /** + * List of errors that occurred executing the mutation. + * @deprecated Use `customerUserErrors` instead + */ + userErrors: Array<UserError> +} + +/** Represents an error that happens during execution of a customer mutation. */ +export type CustomerUserError = DisplayableError & { + __typename?: 'CustomerUserError' + /** Error code to uniquely identify the error. */ + code?: Maybe<CustomerErrorCode> + /** Path to the input field which caused the error. */ + field?: Maybe<Array<Scalars['String']>> + /** The error message. */ + message: Scalars['String'] +} + +/** Digital wallet, such as Apple Pay, which can be used for accelerated checkouts. */ +export enum DigitalWallet { + /** Apple Pay. */ + ApplePay = 'APPLE_PAY', + /** Android Pay. */ + AndroidPay = 'ANDROID_PAY', + /** Google Pay. */ + GooglePay = 'GOOGLE_PAY', + /** Shopify Pay. */ + ShopifyPay = 'SHOPIFY_PAY', +} + +/** An amount discounting the line that has been allocated by a discount. */ +export type DiscountAllocation = { + __typename?: 'DiscountAllocation' + /** Amount of discount allocated. */ + allocatedAmount: MoneyV2 + /** The discount this allocated amount originated from. */ + discountApplication: DiscountApplication +} + +/** + * Discount applications capture the intentions of a discount source at + * the time of application. + */ +export type DiscountApplication = { + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The value of the discount application. */ + value: PricingValue +} + +/** The method by which the discount's value is allocated onto its entitled lines. */ +export enum DiscountApplicationAllocationMethod { + /** The value is spread across all entitled lines. */ + Across = 'ACROSS', + /** The value is applied onto every entitled line. */ + Each = 'EACH', + /** The value is specifically applied onto a particular line. */ + One = 'ONE', +} + +/** An auto-generated type for paginating through multiple DiscountApplications. */ +export type DiscountApplicationConnection = { + __typename?: 'DiscountApplicationConnection' + /** A list of edges. */ + edges: Array<DiscountApplicationEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one DiscountApplication and a cursor during pagination. */ +export type DiscountApplicationEdge = { + __typename?: 'DiscountApplicationEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of DiscountApplicationEdge. */ + node: DiscountApplication +} + +/** + * Which lines on the order that the discount is allocated over, of the type + * defined by the Discount Application's target_type. + */ +export enum DiscountApplicationTargetSelection { + /** The discount is allocated onto all the lines. */ + All = 'ALL', + /** The discount is allocated onto only the lines it is entitled for. */ + Entitled = 'ENTITLED', + /** The discount is allocated onto explicitly chosen lines. */ + Explicit = 'EXPLICIT', +} + +/** The type of line (i.e. line item or shipping line) on an order that the discount is applicable towards. */ +export enum DiscountApplicationTargetType { + /** The discount applies onto line items. */ + LineItem = 'LINE_ITEM', + /** The discount applies onto shipping lines. */ + ShippingLine = 'SHIPPING_LINE', +} + +/** + * Discount code applications capture the intentions of a discount code at + * the time that it is applied. + */ +export type DiscountCodeApplication = DiscountApplication & { + __typename?: 'DiscountCodeApplication' + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** Specifies whether the discount code was applied successfully. */ + applicable: Scalars['Boolean'] + /** The string identifying the discount code that was used at the time of application. */ + code: Scalars['String'] + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The value of the discount application. */ + value: PricingValue +} + +/** Represents an error in the input of a mutation. */ +export type DisplayableError = { + /** Path to the input field which caused the error. */ + field?: Maybe<Array<Scalars['String']>> + /** The error message. */ + message: Scalars['String'] +} + +/** Represents a web address. */ +export type Domain = { + __typename?: 'Domain' + /** The host name of the domain (eg: `example.com`). */ + host: Scalars['String'] + /** Whether SSL is enabled or not. */ + sslEnabled: Scalars['Boolean'] + /** The URL of the domain (eg: `https://example.com`). */ + url: Scalars['URL'] +} + +/** Represents a video hosted outside of Shopify. */ +export type ExternalVideo = Node & + Media & { + __typename?: 'ExternalVideo' + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** The URL. */ + embeddedUrl: Scalars['URL'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> + } + +/** Represents a single fulfillment in an order. */ +export type Fulfillment = { + __typename?: 'Fulfillment' + /** List of the fulfillment's line items. */ + fulfillmentLineItems: FulfillmentLineItemConnection + /** The name of the tracking company. */ + trackingCompany?: Maybe<Scalars['String']> + /** + * Tracking information associated with the fulfillment, + * such as the tracking number and tracking URL. + */ + trackingInfo: Array<FulfillmentTrackingInfo> +} + +/** Represents a single fulfillment in an order. */ +export type FulfillmentFulfillmentLineItemsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** Represents a single fulfillment in an order. */ +export type FulfillmentTrackingInfoArgs = { + first?: Maybe<Scalars['Int']> +} + +/** Represents a single line item in a fulfillment. There is at most one fulfillment line item for each order line item. */ +export type FulfillmentLineItem = { + __typename?: 'FulfillmentLineItem' + /** The associated order's line item. */ + lineItem: OrderLineItem + /** The amount fulfilled in this fulfillment. */ + quantity: Scalars['Int'] +} + +/** An auto-generated type for paginating through multiple FulfillmentLineItems. */ +export type FulfillmentLineItemConnection = { + __typename?: 'FulfillmentLineItemConnection' + /** A list of edges. */ + edges: Array<FulfillmentLineItemEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one FulfillmentLineItem and a cursor during pagination. */ +export type FulfillmentLineItemEdge = { + __typename?: 'FulfillmentLineItemEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of FulfillmentLineItemEdge. */ + node: FulfillmentLineItem +} + +/** Tracking information associated with the fulfillment. */ +export type FulfillmentTrackingInfo = { + __typename?: 'FulfillmentTrackingInfo' + /** The tracking number of the fulfillment. */ + number?: Maybe<Scalars['String']> + /** The URL to track the fulfillment. */ + url?: Maybe<Scalars['URL']> +} + +/** Represents information about the metafields associated to the specified resource. */ +export type HasMetafields = { + /** The metafield associated with the resource. */ + metafield?: Maybe<Metafield> + /** A paginated list of metafields associated with the resource. */ + metafields: MetafieldConnection +} + +/** Represents information about the metafields associated to the specified resource. */ +export type HasMetafieldsMetafieldArgs = { + namespace: Scalars['String'] + key: Scalars['String'] +} + +/** Represents information about the metafields associated to the specified resource. */ +export type HasMetafieldsMetafieldsArgs = { + namespace?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** Represents an image resource. */ +export type Image = { + __typename?: 'Image' + /** A word or phrase to share the nature or contents of an image. */ + altText?: Maybe<Scalars['String']> + /** The original height of the image in pixels. Returns `null` if the image is not hosted by Shopify. */ + height?: Maybe<Scalars['Int']> + /** A unique identifier for the image. */ + id?: Maybe<Scalars['ID']> + /** + * The location of the original image as a URL. + * + * If there are any existing transformations in the original source URL, they will remain and not be stripped. + */ + originalSrc: Scalars['URL'] + /** + * The location of the image as a URL. + * @deprecated Previously an image had a single `src` field. This could either return the original image + * location or a URL that contained transformations such as sizing or scale. + * + * These transformations were specified by arguments on the parent field. + * + * Now an image has two distinct URL fields: `originalSrc` and `transformedSrc`. + * + * * `originalSrc` - the original unmodified image URL + * * `transformedSrc` - the image URL with the specified transformations included + * + * To migrate to the new fields, image transformations should be moved from the parent field to `transformedSrc`. + * + * Before: + * ```graphql + * { + * shop { + * productImages(maxWidth: 200, scale: 2) { + * edges { + * node { + * src + * } + * } + * } + * } + * } + * ``` + * + * After: + * ```graphql + * { + * shop { + * productImages { + * edges { + * node { + * transformedSrc(maxWidth: 200, scale: 2) + * } + * } + * } + * } + * } + * ``` + * + */ + src: Scalars['URL'] + /** + * The location of the transformed image as a URL. + * + * All transformation arguments are considered "best-effort". If they can be applied to an image, they will be. + * Otherwise any transformations which an image type does not support will be ignored. + */ + transformedSrc: Scalars['URL'] + /** The original width of the image in pixels. Returns `null` if the image is not hosted by Shopify. */ + width?: Maybe<Scalars['Int']> +} + +/** Represents an image resource. */ +export type ImageTransformedSrcArgs = { + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> + preferredContentType?: Maybe<ImageContentType> +} + +/** An auto-generated type for paginating through multiple Images. */ +export type ImageConnection = { + __typename?: 'ImageConnection' + /** A list of edges. */ + edges: Array<ImageEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** List of supported image content types. */ +export enum ImageContentType { + /** A PNG image. */ + Png = 'PNG', + /** A JPG image. */ + Jpg = 'JPG', + /** A WEBP image. */ + Webp = 'WEBP', +} + +/** An auto-generated type which holds one Image and a cursor during pagination. */ +export type ImageEdge = { + __typename?: 'ImageEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ImageEdge. */ + node: Image +} + +/** Represents a mailing address for customers and shipping. */ +export type MailingAddress = Node & { + __typename?: 'MailingAddress' + /** The first line of the address. Typically the street address or PO Box number. */ + address1?: Maybe<Scalars['String']> + /** The second line of the address. Typically the number of the apartment, suite, or unit. */ + address2?: Maybe<Scalars['String']> + /** The name of the city, district, village, or town. */ + city?: Maybe<Scalars['String']> + /** The name of the customer's company or organization. */ + company?: Maybe<Scalars['String']> + /** The name of the country. */ + country?: Maybe<Scalars['String']> + /** + * The two-letter code for the country of the address. + * + * For example, US. + * @deprecated Use `countryCodeV2` instead + */ + countryCode?: Maybe<Scalars['String']> + /** + * The two-letter code for the country of the address. + * + * For example, US. + */ + countryCodeV2?: Maybe<CountryCode> + /** The first name of the customer. */ + firstName?: Maybe<Scalars['String']> + /** A formatted version of the address, customized by the provided arguments. */ + formatted: Array<Scalars['String']> + /** A comma-separated list of the values for city, province, and country. */ + formattedArea?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The last name of the customer. */ + lastName?: Maybe<Scalars['String']> + /** The latitude coordinate of the customer address. */ + latitude?: Maybe<Scalars['Float']> + /** The longitude coordinate of the customer address. */ + longitude?: Maybe<Scalars['Float']> + /** The full name of the customer, based on firstName and lastName. */ + name?: Maybe<Scalars['String']> + /** + * A unique phone number for the customer. + * + * Formatted using E.164 standard. For example, _+16135551111_. + */ + phone?: Maybe<Scalars['String']> + /** The region of the address, such as the province, state, or district. */ + province?: Maybe<Scalars['String']> + /** + * The two-letter code for the region. + * + * For example, ON. + */ + provinceCode?: Maybe<Scalars['String']> + /** The zip or postal code of the address. */ + zip?: Maybe<Scalars['String']> +} + +/** Represents a mailing address for customers and shipping. */ +export type MailingAddressFormattedArgs = { + withName?: Maybe<Scalars['Boolean']> + withCompany?: Maybe<Scalars['Boolean']> +} + +/** An auto-generated type for paginating through multiple MailingAddresses. */ +export type MailingAddressConnection = { + __typename?: 'MailingAddressConnection' + /** A list of edges. */ + edges: Array<MailingAddressEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one MailingAddress and a cursor during pagination. */ +export type MailingAddressEdge = { + __typename?: 'MailingAddressEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of MailingAddressEdge. */ + node: MailingAddress +} + +/** Specifies the fields accepted to create or update a mailing address. */ +export type MailingAddressInput = { + /** The first line of the address. Typically the street address or PO Box number. */ + address1?: Maybe<Scalars['String']> + /** The second line of the address. Typically the number of the apartment, suite, or unit. */ + address2?: Maybe<Scalars['String']> + /** The name of the city, district, village, or town. */ + city?: Maybe<Scalars['String']> + /** The name of the customer's company or organization. */ + company?: Maybe<Scalars['String']> + /** The name of the country. */ + country?: Maybe<Scalars['String']> + /** The first name of the customer. */ + firstName?: Maybe<Scalars['String']> + /** The last name of the customer. */ + lastName?: Maybe<Scalars['String']> + /** + * A unique phone number for the customer. + * + * Formatted using E.164 standard. For example, _+16135551111_. + */ + phone?: Maybe<Scalars['String']> + /** The region of the address, such as the province, state, or district. */ + province?: Maybe<Scalars['String']> + /** The zip or postal code of the address. */ + zip?: Maybe<Scalars['String']> +} + +/** Manual discount applications capture the intentions of a discount that was manually created. */ +export type ManualDiscountApplication = DiscountApplication & { + __typename?: 'ManualDiscountApplication' + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** The description of the application. */ + description?: Maybe<Scalars['String']> + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The title of the application. */ + title: Scalars['String'] + /** The value of the discount application. */ + value: PricingValue +} + +/** Represents a media interface. */ +export type Media = { + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> +} + +/** An auto-generated type for paginating through multiple Media. */ +export type MediaConnection = { + __typename?: 'MediaConnection' + /** A list of edges. */ + edges: Array<MediaEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** The possible content types for a media object. */ +export enum MediaContentType { + /** An externally hosted video. */ + ExternalVideo = 'EXTERNAL_VIDEO', + /** A Shopify hosted image. */ + Image = 'IMAGE', + /** A 3d model. */ + Model_3D = 'MODEL_3D', + /** A Shopify hosted video. */ + Video = 'VIDEO', +} + +/** An auto-generated type which holds one Media and a cursor during pagination. */ +export type MediaEdge = { + __typename?: 'MediaEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of MediaEdge. */ + node: Media +} + +/** Represents a Shopify hosted image. */ +export type MediaImage = Node & + Media & { + __typename?: 'MediaImage' + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The image for the media. */ + image?: Maybe<Image> + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> + } + +/** + * Metafields represent custom metadata attached to a resource. Metafields can be sorted into namespaces and are + * comprised of keys, values, and value types. + */ +export type Metafield = Node & { + __typename?: 'Metafield' + /** The date and time when the storefront metafield was created. */ + createdAt: Scalars['DateTime'] + /** The description of a metafield. */ + description?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The key name for a metafield. */ + key: Scalars['String'] + /** The namespace for a metafield. */ + namespace: Scalars['String'] + /** The parent object that the metafield belongs to. */ + parentResource: MetafieldParentResource + /** The date and time when the storefront metafield was updated. */ + updatedAt: Scalars['DateTime'] + /** The value of a metafield. */ + value: Scalars['String'] + /** Represents the metafield value type. */ + valueType: MetafieldValueType +} + +/** An auto-generated type for paginating through multiple Metafields. */ +export type MetafieldConnection = { + __typename?: 'MetafieldConnection' + /** A list of edges. */ + edges: Array<MetafieldEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Metafield and a cursor during pagination. */ +export type MetafieldEdge = { + __typename?: 'MetafieldEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of MetafieldEdge. */ + node: Metafield +} + +/** A resource that the metafield belongs to. */ +export type MetafieldParentResource = Product | ProductVariant + +/** Metafield value types. */ +export enum MetafieldValueType { + /** A string metafield. */ + String = 'STRING', + /** An integer metafield. */ + Integer = 'INTEGER', + /** A json string metafield. */ + JsonString = 'JSON_STRING', +} + +/** Represents a Shopify hosted 3D model. */ +export type Model3d = Node & + Media & { + __typename?: 'Model3d' + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> + /** The sources for a 3d model. */ + sources: Array<Model3dSource> + } + +/** Represents a source for a Shopify hosted 3d model. */ +export type Model3dSource = { + __typename?: 'Model3dSource' + /** The filesize of the 3d model. */ + filesize: Scalars['Int'] + /** The format of the 3d model. */ + format: Scalars['String'] + /** The MIME type of the 3d model. */ + mimeType: Scalars['String'] + /** The URL of the 3d model. */ + url: Scalars['String'] +} + +/** Specifies the fields for a monetary value with currency. */ +export type MoneyInput = { + /** Decimal money amount. */ + amount: Scalars['Decimal'] + /** Currency of the money. */ + currencyCode: CurrencyCode +} + +/** + * A monetary value with currency. + * + * To format currencies, combine this type's amount and currencyCode fields with your client's locale. + * + * For example, in JavaScript you could use Intl.NumberFormat: + * + * ```js + * new Intl.NumberFormat(locale, { + * style: 'currency', + * currency: currencyCode + * }).format(amount); + * ``` + * + * Other formatting libraries include: + * + * * iOS - [NumberFormatter](https://developer.apple.com/documentation/foundation/numberformatter) + * * Android - [NumberFormat](https://developer.android.com/reference/java/text/NumberFormat.html) + * * PHP - [NumberFormatter](http://php.net/manual/en/class.numberformatter.php) + * + * For a more general solution, the [Unicode CLDR number formatting database] is available with many implementations + * (such as [TwitterCldr](https://github.com/twitter/twitter-cldr-rb)). + */ +export type MoneyV2 = { + __typename?: 'MoneyV2' + /** Decimal money amount. */ + amount: Scalars['Decimal'] + /** Currency of the money. */ + currencyCode: CurrencyCode +} + +/** An auto-generated type for paginating through multiple MoneyV2s. */ +export type MoneyV2Connection = { + __typename?: 'MoneyV2Connection' + /** A list of edges. */ + edges: Array<MoneyV2Edge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one MoneyV2 and a cursor during pagination. */ +export type MoneyV2Edge = { + __typename?: 'MoneyV2Edge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of MoneyV2Edge. */ + node: MoneyV2 +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type Mutation = { + __typename?: 'Mutation' + /** + * Updates the attributes of a checkout. + * @deprecated Use `checkoutAttributesUpdateV2` instead + */ + checkoutAttributesUpdate?: Maybe<CheckoutAttributesUpdatePayload> + /** Updates the attributes of a checkout. */ + checkoutAttributesUpdateV2?: Maybe<CheckoutAttributesUpdateV2Payload> + /** Completes a checkout without providing payment information. You can use this mutation for free items or items whose purchase price is covered by a gift card. */ + checkoutCompleteFree?: Maybe<CheckoutCompleteFreePayload> + /** + * Completes a checkout using a credit card token from Shopify's Vault. + * @deprecated Use `checkoutCompleteWithCreditCardV2` instead + */ + checkoutCompleteWithCreditCard?: Maybe<CheckoutCompleteWithCreditCardPayload> + /** Completes a checkout using a credit card token from Shopify's card vault. Before you can complete checkouts using CheckoutCompleteWithCreditCardV2, you need to [_request payment processing_](https://help.shopify.com/api/guides/sales-channel-sdk/getting-started#request-payment-processing). */ + checkoutCompleteWithCreditCardV2?: Maybe<CheckoutCompleteWithCreditCardV2Payload> + /** + * Completes a checkout with a tokenized payment. + * @deprecated Use `checkoutCompleteWithTokenizedPaymentV2` instead + */ + checkoutCompleteWithTokenizedPayment?: Maybe<CheckoutCompleteWithTokenizedPaymentPayload> + /** + * Completes a checkout with a tokenized payment. + * @deprecated Use `checkoutCompleteWithTokenizedPaymentV3` instead + */ + checkoutCompleteWithTokenizedPaymentV2?: Maybe<CheckoutCompleteWithTokenizedPaymentV2Payload> + /** Completes a checkout with a tokenized payment. */ + checkoutCompleteWithTokenizedPaymentV3?: Maybe<CheckoutCompleteWithTokenizedPaymentV3Payload> + /** Creates a new checkout. */ + checkoutCreate?: Maybe<CheckoutCreatePayload> + /** + * Associates a customer to the checkout. + * @deprecated Use `checkoutCustomerAssociateV2` instead + */ + checkoutCustomerAssociate?: Maybe<CheckoutCustomerAssociatePayload> + /** Associates a customer to the checkout. */ + checkoutCustomerAssociateV2?: Maybe<CheckoutCustomerAssociateV2Payload> + /** + * Disassociates the current checkout customer from the checkout. + * @deprecated Use `checkoutCustomerDisassociateV2` instead + */ + checkoutCustomerDisassociate?: Maybe<CheckoutCustomerDisassociatePayload> + /** Disassociates the current checkout customer from the checkout. */ + checkoutCustomerDisassociateV2?: Maybe<CheckoutCustomerDisassociateV2Payload> + /** + * Applies a discount to an existing checkout using a discount code. + * @deprecated Use `checkoutDiscountCodeApplyV2` instead + */ + checkoutDiscountCodeApply?: Maybe<CheckoutDiscountCodeApplyPayload> + /** Applies a discount to an existing checkout using a discount code. */ + checkoutDiscountCodeApplyV2?: Maybe<CheckoutDiscountCodeApplyV2Payload> + /** Removes the applied discount from an existing checkout. */ + checkoutDiscountCodeRemove?: Maybe<CheckoutDiscountCodeRemovePayload> + /** + * Updates the email on an existing checkout. + * @deprecated Use `checkoutEmailUpdateV2` instead + */ + checkoutEmailUpdate?: Maybe<CheckoutEmailUpdatePayload> + /** Updates the email on an existing checkout. */ + checkoutEmailUpdateV2?: Maybe<CheckoutEmailUpdateV2Payload> + /** + * Applies a gift card to an existing checkout using a gift card code. This will replace all currently applied gift cards. + * @deprecated Use `checkoutGiftCardsAppend` instead + */ + checkoutGiftCardApply?: Maybe<CheckoutGiftCardApplyPayload> + /** + * Removes an applied gift card from the checkout. + * @deprecated Use `checkoutGiftCardRemoveV2` instead + */ + checkoutGiftCardRemove?: Maybe<CheckoutGiftCardRemovePayload> + /** Removes an applied gift card from the checkout. */ + checkoutGiftCardRemoveV2?: Maybe<CheckoutGiftCardRemoveV2Payload> + /** Appends gift cards to an existing checkout. */ + checkoutGiftCardsAppend?: Maybe<CheckoutGiftCardsAppendPayload> + /** Adds a list of line items to a checkout. */ + checkoutLineItemsAdd?: Maybe<CheckoutLineItemsAddPayload> + /** Removes line items from an existing checkout. */ + checkoutLineItemsRemove?: Maybe<CheckoutLineItemsRemovePayload> + /** Sets a list of line items to a checkout. */ + checkoutLineItemsReplace?: Maybe<CheckoutLineItemsReplacePayload> + /** Updates line items on a checkout. */ + checkoutLineItemsUpdate?: Maybe<CheckoutLineItemsUpdatePayload> + /** + * Updates the shipping address of an existing checkout. + * @deprecated Use `checkoutShippingAddressUpdateV2` instead + */ + checkoutShippingAddressUpdate?: Maybe<CheckoutShippingAddressUpdatePayload> + /** Updates the shipping address of an existing checkout. */ + checkoutShippingAddressUpdateV2?: Maybe<CheckoutShippingAddressUpdateV2Payload> + /** Updates the shipping lines on an existing checkout. */ + checkoutShippingLineUpdate?: Maybe<CheckoutShippingLineUpdatePayload> + /** + * Creates a customer access token. + * The customer access token is required to modify the customer object in any way. + */ + customerAccessTokenCreate?: Maybe<CustomerAccessTokenCreatePayload> + /** + * Creates a customer access token using a multipass token instead of email and password. + * A customer record is created if customer does not exist. If a customer record already + * exists but the record is disabled, then it's enabled. + */ + customerAccessTokenCreateWithMultipass?: Maybe<CustomerAccessTokenCreateWithMultipassPayload> + /** Permanently destroys a customer access token. */ + customerAccessTokenDelete?: Maybe<CustomerAccessTokenDeletePayload> + /** + * Renews a customer access token. + * + * Access token renewal must happen *before* a token expires. + * If a token has already expired, a new one should be created instead via `customerAccessTokenCreate`. + */ + customerAccessTokenRenew?: Maybe<CustomerAccessTokenRenewPayload> + /** Activates a customer. */ + customerActivate?: Maybe<CustomerActivatePayload> + /** Activates a customer with the activation url received from `customerCreate`. */ + customerActivateByUrl?: Maybe<CustomerActivateByUrlPayload> + /** Creates a new address for a customer. */ + customerAddressCreate?: Maybe<CustomerAddressCreatePayload> + /** Permanently deletes the address of an existing customer. */ + customerAddressDelete?: Maybe<CustomerAddressDeletePayload> + /** Updates the address of an existing customer. */ + customerAddressUpdate?: Maybe<CustomerAddressUpdatePayload> + /** Creates a new customer. */ + customerCreate?: Maybe<CustomerCreatePayload> + /** Updates the default address of an existing customer. */ + customerDefaultAddressUpdate?: Maybe<CustomerDefaultAddressUpdatePayload> + /** Sends a reset password email to the customer, as the first step in the reset password process. */ + customerRecover?: Maybe<CustomerRecoverPayload> + /** Resets a customer’s password with a token received from `CustomerRecover`. */ + customerReset?: Maybe<CustomerResetPayload> + /** Resets a customer’s password with the reset password url received from `CustomerRecover`. */ + customerResetByUrl?: Maybe<CustomerResetByUrlPayload> + /** Updates an existing customer. */ + customerUpdate?: Maybe<CustomerUpdatePayload> +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutAttributesUpdateArgs = { + checkoutId: Scalars['ID'] + input: CheckoutAttributesUpdateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutAttributesUpdateV2Args = { + checkoutId: Scalars['ID'] + input: CheckoutAttributesUpdateV2Input +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteFreeArgs = { + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithCreditCardArgs = { + checkoutId: Scalars['ID'] + payment: CreditCardPaymentInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithCreditCardV2Args = { + checkoutId: Scalars['ID'] + payment: CreditCardPaymentInputV2 +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithTokenizedPaymentArgs = { + checkoutId: Scalars['ID'] + payment: TokenizedPaymentInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithTokenizedPaymentV2Args = { + checkoutId: Scalars['ID'] + payment: TokenizedPaymentInputV2 +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCompleteWithTokenizedPaymentV3Args = { + checkoutId: Scalars['ID'] + payment: TokenizedPaymentInputV3 +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCreateArgs = { + input: CheckoutCreateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCustomerAssociateArgs = { + checkoutId: Scalars['ID'] + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCustomerAssociateV2Args = { + checkoutId: Scalars['ID'] + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCustomerDisassociateArgs = { + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutCustomerDisassociateV2Args = { + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutDiscountCodeApplyArgs = { + discountCode: Scalars['String'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutDiscountCodeApplyV2Args = { + discountCode: Scalars['String'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutDiscountCodeRemoveArgs = { + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutEmailUpdateArgs = { + checkoutId: Scalars['ID'] + email: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutEmailUpdateV2Args = { + checkoutId: Scalars['ID'] + email: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutGiftCardApplyArgs = { + giftCardCode: Scalars['String'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutGiftCardRemoveArgs = { + appliedGiftCardId: Scalars['ID'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutGiftCardRemoveV2Args = { + appliedGiftCardId: Scalars['ID'] + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutGiftCardsAppendArgs = { + giftCardCodes: Array<Scalars['String']> + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutLineItemsAddArgs = { + lineItems: Array<CheckoutLineItemInput> + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutLineItemsRemoveArgs = { + checkoutId: Scalars['ID'] + lineItemIds: Array<Scalars['ID']> +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutLineItemsReplaceArgs = { + lineItems: Array<CheckoutLineItemInput> + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutLineItemsUpdateArgs = { + checkoutId: Scalars['ID'] + lineItems: Array<CheckoutLineItemUpdateInput> +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutShippingAddressUpdateArgs = { + shippingAddress: MailingAddressInput + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutShippingAddressUpdateV2Args = { + shippingAddress: MailingAddressInput + checkoutId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCheckoutShippingLineUpdateArgs = { + checkoutId: Scalars['ID'] + shippingRateHandle: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAccessTokenCreateArgs = { + input: CustomerAccessTokenCreateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAccessTokenCreateWithMultipassArgs = { + multipassToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAccessTokenDeleteArgs = { + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAccessTokenRenewArgs = { + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerActivateArgs = { + id: Scalars['ID'] + input: CustomerActivateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerActivateByUrlArgs = { + activationUrl: Scalars['URL'] + password: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAddressCreateArgs = { + customerAccessToken: Scalars['String'] + address: MailingAddressInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAddressDeleteArgs = { + id: Scalars['ID'] + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerAddressUpdateArgs = { + customerAccessToken: Scalars['String'] + id: Scalars['ID'] + address: MailingAddressInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerCreateArgs = { + input: CustomerCreateInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerDefaultAddressUpdateArgs = { + customerAccessToken: Scalars['String'] + addressId: Scalars['ID'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerRecoverArgs = { + email: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerResetArgs = { + id: Scalars['ID'] + input: CustomerResetInput +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerResetByUrlArgs = { + resetUrl: Scalars['URL'] + password: Scalars['String'] +} + +/** The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. */ +export type MutationCustomerUpdateArgs = { + customerAccessToken: Scalars['String'] + customer: CustomerUpdateInput +} + +/** An object with an ID to support global identification. */ +export type Node = { + /** Globally unique identifier. */ + id: Scalars['ID'] +} + +/** An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. */ +export type Order = Node & { + __typename?: 'Order' + /** The reason for the order's cancellation. Returns `null` if the order wasn't canceled. */ + cancelReason?: Maybe<OrderCancelReason> + /** The date and time when the order was canceled. Returns null if the order wasn't canceled. */ + canceledAt?: Maybe<Scalars['DateTime']> + /** The code of the currency used for the payment. */ + currencyCode: CurrencyCode + /** The subtotal of line items and their discounts, excluding line items that have been removed. Does not contain order-level discounts, duties, shipping costs, or shipping discounts. Taxes are not included unless the order is a taxes-included order. */ + currentSubtotalPrice: MoneyV2 + /** The total amount of the order, including duties, taxes and discounts, minus amounts for line items that have been removed. */ + currentTotalPrice: MoneyV2 + /** The total of all taxes applied to the order, excluding taxes for returned line items. */ + currentTotalTax: MoneyV2 + /** The locale code in which this specific order happened. */ + customerLocale?: Maybe<Scalars['String']> + /** The unique URL that the customer can use to access the order. */ + customerUrl?: Maybe<Scalars['URL']> + /** Discounts that have been applied on the order. */ + discountApplications: DiscountApplicationConnection + /** Whether the order has had any edits applied or not. */ + edited: Scalars['Boolean'] + /** The customer's email address. */ + email?: Maybe<Scalars['String']> + /** The financial status of the order. */ + financialStatus?: Maybe<OrderFinancialStatus> + /** The fulfillment status for the order. */ + fulfillmentStatus: OrderFulfillmentStatus + /** Globally unique identifier. */ + id: Scalars['ID'] + /** List of the order’s line items. */ + lineItems: OrderLineItemConnection + /** + * Unique identifier for the order that appears on the order. + * For example, _#1000_ or _Store1001. + */ + name: Scalars['String'] + /** A unique numeric identifier for the order for use by shop owner and customer. */ + orderNumber: Scalars['Int'] + /** The total price of the order before any applied edits. */ + originalTotalPrice: MoneyV2 + /** The customer's phone number for receiving SMS notifications. */ + phone?: Maybe<Scalars['String']> + /** + * The date and time when the order was imported. + * This value can be set to dates in the past when importing from other systems. + * If no value is provided, it will be auto-generated based on current date and time. + */ + processedAt: Scalars['DateTime'] + /** The address to where the order will be shipped. */ + shippingAddress?: Maybe<MailingAddress> + /** The discounts that have been allocated onto the shipping line by discount applications. */ + shippingDiscountAllocations: Array<DiscountAllocation> + /** The unique URL for the order's status page. */ + statusUrl: Scalars['URL'] + /** + * Price of the order before shipping and taxes. + * @deprecated Use `subtotalPriceV2` instead + */ + subtotalPrice?: Maybe<Scalars['Money']> + /** Price of the order before duties, shipping and taxes. */ + subtotalPriceV2?: Maybe<MoneyV2> + /** List of the order’s successful fulfillments. */ + successfulFulfillments?: Maybe<Array<Fulfillment>> + /** + * The sum of all the prices of all the items in the order, taxes and discounts included (must be positive). + * @deprecated Use `totalPriceV2` instead + */ + totalPrice: Scalars['Money'] + /** The sum of all the prices of all the items in the order, duties, taxes and discounts included (must be positive). */ + totalPriceV2: MoneyV2 + /** + * The total amount that has been refunded. + * @deprecated Use `totalRefundedV2` instead + */ + totalRefunded: Scalars['Money'] + /** The total amount that has been refunded. */ + totalRefundedV2: MoneyV2 + /** + * The total cost of shipping. + * @deprecated Use `totalShippingPriceV2` instead + */ + totalShippingPrice: Scalars['Money'] + /** The total cost of shipping. */ + totalShippingPriceV2: MoneyV2 + /** + * The total cost of taxes. + * @deprecated Use `totalTaxV2` instead + */ + totalTax?: Maybe<Scalars['Money']> + /** The total cost of taxes. */ + totalTaxV2?: Maybe<MoneyV2> +} + +/** An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. */ +export type OrderDiscountApplicationsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. */ +export type OrderLineItemsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. */ +export type OrderSuccessfulFulfillmentsArgs = { + first?: Maybe<Scalars['Int']> +} + +/** Represents the reason for the order's cancellation. */ +export enum OrderCancelReason { + /** The customer wanted to cancel the order. */ + Customer = 'CUSTOMER', + /** The order was fraudulent. */ + Fraud = 'FRAUD', + /** There was insufficient inventory. */ + Inventory = 'INVENTORY', + /** Payment was declined. */ + Declined = 'DECLINED', + /** The order was canceled for an unlisted reason. */ + Other = 'OTHER', +} + +/** An auto-generated type for paginating through multiple Orders. */ +export type OrderConnection = { + __typename?: 'OrderConnection' + /** A list of edges. */ + edges: Array<OrderEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Order and a cursor during pagination. */ +export type OrderEdge = { + __typename?: 'OrderEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of OrderEdge. */ + node: Order +} + +/** Represents the order's current financial status. */ +export enum OrderFinancialStatus { + /** Displayed as **Pending**. */ + Pending = 'PENDING', + /** Displayed as **Authorized**. */ + Authorized = 'AUTHORIZED', + /** Displayed as **Partially paid**. */ + PartiallyPaid = 'PARTIALLY_PAID', + /** Displayed as **Partially refunded**. */ + PartiallyRefunded = 'PARTIALLY_REFUNDED', + /** Displayed as **Voided**. */ + Voided = 'VOIDED', + /** Displayed as **Paid**. */ + Paid = 'PAID', + /** Displayed as **Refunded**. */ + Refunded = 'REFUNDED', +} + +/** Represents the order's current fulfillment status. */ +export enum OrderFulfillmentStatus { + /** Displayed as **Unfulfilled**. */ + Unfulfilled = 'UNFULFILLED', + /** Displayed as **Partially fulfilled**. */ + PartiallyFulfilled = 'PARTIALLY_FULFILLED', + /** Displayed as **Fulfilled**. */ + Fulfilled = 'FULFILLED', + /** Displayed as **Restocked**. */ + Restocked = 'RESTOCKED', + /** Displayed as **Pending fulfillment**. */ + PendingFulfillment = 'PENDING_FULFILLMENT', + /** Displayed as **Open**. */ + Open = 'OPEN', + /** Displayed as **In progress**. */ + InProgress = 'IN_PROGRESS', + /** Displayed as **Scheduled**. */ + Scheduled = 'SCHEDULED', +} + +/** Represents a single line in an order. There is one line item for each distinct product variant. */ +export type OrderLineItem = { + __typename?: 'OrderLineItem' + /** The number of entries associated to the line item minus the items that have been removed. */ + currentQuantity: Scalars['Int'] + /** List of custom attributes associated to the line item. */ + customAttributes: Array<Attribute> + /** The discounts that have been allocated onto the order line item by discount applications. */ + discountAllocations: Array<DiscountAllocation> + /** The total price of the line item, including discounts, and displayed in the presentment currency. */ + discountedTotalPrice: MoneyV2 + /** The total price of the line item, not including any discounts. The total price is calculated using the original unit price multiplied by the quantity, and it is displayed in the presentment currency. */ + originalTotalPrice: MoneyV2 + /** The number of products variants associated to the line item. */ + quantity: Scalars['Int'] + /** The title of the product combined with title of the variant. */ + title: Scalars['String'] + /** The product variant object associated to the line item. */ + variant?: Maybe<ProductVariant> +} + +/** An auto-generated type for paginating through multiple OrderLineItems. */ +export type OrderLineItemConnection = { + __typename?: 'OrderLineItemConnection' + /** A list of edges. */ + edges: Array<OrderLineItemEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one OrderLineItem and a cursor during pagination. */ +export type OrderLineItemEdge = { + __typename?: 'OrderLineItemEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of OrderLineItemEdge. */ + node: OrderLineItem +} + +/** The set of valid sort keys for the Order query. */ +export enum OrderSortKeys { + /** Sort by the `processed_at` value. */ + ProcessedAt = 'PROCESSED_AT', + /** Sort by the `total_price` value. */ + TotalPrice = 'TOTAL_PRICE', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** Shopify merchants can create pages to hold static HTML content. Each Page object represents a custom page on the online store. */ +export type Page = Node & { + __typename?: 'Page' + /** The description of the page, complete with HTML formatting. */ + body: Scalars['HTML'] + /** Summary of the page body. */ + bodySummary: Scalars['String'] + /** The timestamp of the page creation. */ + createdAt: Scalars['DateTime'] + /** A human-friendly unique string for the page automatically generated from its title. */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The page's SEO information. */ + seo?: Maybe<Seo> + /** The title of the page. */ + title: Scalars['String'] + /** The timestamp of the latest page update. */ + updatedAt: Scalars['DateTime'] + /** The url pointing to the page accessible from the web. */ + url: Scalars['URL'] +} + +/** An auto-generated type for paginating through multiple Pages. */ +export type PageConnection = { + __typename?: 'PageConnection' + /** A list of edges. */ + edges: Array<PageEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Page and a cursor during pagination. */ +export type PageEdge = { + __typename?: 'PageEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of PageEdge. */ + node: Page +} + +/** Information about pagination in a connection. */ +export type PageInfo = { + __typename?: 'PageInfo' + /** Indicates if there are more pages to fetch. */ + hasNextPage: Scalars['Boolean'] + /** Indicates if there are any pages prior to the current page. */ + hasPreviousPage: Scalars['Boolean'] +} + +/** The set of valid sort keys for the Page query. */ +export enum PageSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `updated_at` value. */ + UpdatedAt = 'UPDATED_AT', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** A payment applied to a checkout. */ +export type Payment = Node & { + __typename?: 'Payment' + /** + * The amount of the payment. + * @deprecated Use `amountV2` instead + */ + amount: Scalars['Money'] + /** The amount of the payment. */ + amountV2: MoneyV2 + /** The billing address for the payment. */ + billingAddress?: Maybe<MailingAddress> + /** The checkout to which the payment belongs. */ + checkout: Checkout + /** The credit card used for the payment in the case of direct payments. */ + creditCard?: Maybe<CreditCard> + /** A message describing a processing error during asynchronous processing. */ + errorMessage?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** A client-side generated token to identify a payment and perform idempotent operations. */ + idempotencyKey?: Maybe<Scalars['String']> + /** The URL where the customer needs to be redirected so they can complete the 3D Secure payment flow. */ + nextActionUrl?: Maybe<Scalars['URL']> + /** Whether or not the payment is still processing asynchronously. */ + ready: Scalars['Boolean'] + /** A flag to indicate if the payment is to be done in test mode for gateways that support it. */ + test: Scalars['Boolean'] + /** The actual transaction recorded by Shopify after having processed the payment with the gateway. */ + transaction?: Maybe<Transaction> +} + +/** Settings related to payments. */ +export type PaymentSettings = { + __typename?: 'PaymentSettings' + /** List of the card brands which the shop accepts. */ + acceptedCardBrands: Array<CardBrand> + /** The url pointing to the endpoint to vault credit cards. */ + cardVaultUrl: Scalars['URL'] + /** The country where the shop is located. */ + countryCode: CountryCode + /** The three-letter code for the shop's primary currency. */ + currencyCode: CurrencyCode + /** A list of enabled currencies (ISO 4217 format) that the shop accepts. Merchants can enable currencies from their Shopify Payments settings in the Shopify admin. */ + enabledPresentmentCurrencies: Array<CurrencyCode> + /** The shop’s Shopify Payments account id. */ + shopifyPaymentsAccountId?: Maybe<Scalars['String']> + /** List of the digital wallets which the shop supports. */ + supportedDigitalWallets: Array<DigitalWallet> +} + +/** The valid values for the types of payment token. */ +export enum PaymentTokenType { + /** Apple Pay token type. */ + ApplePay = 'APPLE_PAY', + /** Vault payment token type. */ + Vault = 'VAULT', + /** Shopify Pay token type. */ + ShopifyPay = 'SHOPIFY_PAY', + /** Google Pay token type. */ + GooglePay = 'GOOGLE_PAY', +} + +/** The value of the percentage pricing object. */ +export type PricingPercentageValue = { + __typename?: 'PricingPercentageValue' + /** The percentage value of the object. */ + percentage: Scalars['Float'] +} + +/** The price value (fixed or percentage) for a discount application. */ +export type PricingValue = MoneyV2 | PricingPercentageValue + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type Product = Node & + HasMetafields & { + __typename?: 'Product' + /** Indicates if at least one product variant is available for sale. */ + availableForSale: Scalars['Boolean'] + /** List of collections a product belongs to. */ + collections: CollectionConnection + /** The compare at price of the product across all variants. */ + compareAtPriceRange: ProductPriceRange + /** The date and time when the product was created. */ + createdAt: Scalars['DateTime'] + /** Stripped description of the product, single line with HTML tags removed. */ + description: Scalars['String'] + /** The description of the product, complete with HTML formatting. */ + descriptionHtml: Scalars['HTML'] + /** + * A human-friendly unique string for the Product automatically generated from its title. + * They are used by the Liquid templating language to refer to objects. + */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** List of images associated with the product. */ + images: ImageConnection + /** The media associated with the product. */ + media: MediaConnection + /** The metafield associated with the resource. */ + metafield?: Maybe<Metafield> + /** A paginated list of metafields associated with the resource. */ + metafields: MetafieldConnection + /** + * The online store URL for the product. + * A value of `null` indicates that the product is not published to the Online Store sales channel. + */ + onlineStoreUrl?: Maybe<Scalars['URL']> + /** List of product options. */ + options: Array<ProductOption> + /** List of price ranges in the presentment currencies for this shop. */ + presentmentPriceRanges: ProductPriceRangeConnection + /** The price range. */ + priceRange: ProductPriceRange + /** A categorization that a product can be tagged with, commonly used for filtering and searching. */ + productType: Scalars['String'] + /** The date and time when the product was published to the channel. */ + publishedAt: Scalars['DateTime'] + /** The product's SEO information. */ + seo: Seo + /** + * A comma separated list of tags that have been added to the product. + * Additional access scope required for private apps: unauthenticated_read_product_tags. + */ + tags: Array<Scalars['String']> + /** The product’s title. */ + title: Scalars['String'] + /** The total quantity of inventory in stock for this Product. */ + totalInventory?: Maybe<Scalars['Int']> + /** + * The date and time when the product was last modified. + * A product's `updatedAt` value can change for different reasons. For example, if an order + * is placed for a product that has inventory tracking set up, then the inventory adjustment + * is counted as an update. + */ + updatedAt: Scalars['DateTime'] + /** + * Find a product’s variant based on its selected options. + * This is useful for converting a user’s selection of product options into a single matching variant. + * If there is not a variant for the selected options, `null` will be returned. + */ + variantBySelectedOptions?: Maybe<ProductVariant> + /** List of the product’s variants. */ + variants: ProductVariantConnection + /** The product’s vendor name. */ + vendor: Scalars['String'] + } + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductCollectionsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductDescriptionArgs = { + truncateAt?: Maybe<Scalars['Int']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductImagesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductImageSortKeys> + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductMediaArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductMediaSortKeys> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductMetafieldArgs = { + namespace: Scalars['String'] + key: Scalars['String'] +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductMetafieldsArgs = { + namespace?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductOptionsArgs = { + first?: Maybe<Scalars['Int']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductPresentmentPriceRangesArgs = { + presentmentCurrencies?: Maybe<Array<CurrencyCode>> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductVariantBySelectedOptionsArgs = { + selectedOptions: Array<SelectedOptionInput> +} + +/** + * A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. + * For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). + */ +export type ProductVariantsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductVariantSortKeys> +} + +/** The set of valid sort keys for the ProductCollection query. */ +export enum ProductCollectionSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `price` value. */ + Price = 'PRICE', + /** Sort by the `best-selling` value. */ + BestSelling = 'BEST_SELLING', + /** Sort by the `created` value. */ + Created = 'CREATED', + /** Sort by the `id` value. */ + Id = 'ID', + /** Sort by the `manual` value. */ + Manual = 'MANUAL', + /** Sort by the `collection-default` value. */ + CollectionDefault = 'COLLECTION_DEFAULT', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** An auto-generated type for paginating through multiple Products. */ +export type ProductConnection = { + __typename?: 'ProductConnection' + /** A list of edges. */ + edges: Array<ProductEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one Product and a cursor during pagination. */ +export type ProductEdge = { + __typename?: 'ProductEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ProductEdge. */ + node: Product +} + +/** The set of valid sort keys for the ProductImage query. */ +export enum ProductImageSortKeys { + /** Sort by the `created_at` value. */ + CreatedAt = 'CREATED_AT', + /** Sort by the `position` value. */ + Position = 'POSITION', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** The set of valid sort keys for the ProductMedia query. */ +export enum ProductMediaSortKeys { + /** Sort by the `position` value. */ + Position = 'POSITION', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** + * Product property names like "Size", "Color", and "Material" that the customers can select. + * Variants are selected based on permutations of these options. + * 255 characters limit each. + */ +export type ProductOption = Node & { + __typename?: 'ProductOption' + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The product option’s name. */ + name: Scalars['String'] + /** The corresponding value to the product option name. */ + values: Array<Scalars['Object']> +} + +/** The price range of the product. */ +export type ProductPriceRange = { + __typename?: 'ProductPriceRange' + /** The highest variant's price. */ + maxVariantPrice: MoneyV2 + /** The lowest variant's price. */ + minVariantPrice: MoneyV2 +} + +/** An auto-generated type for paginating through multiple ProductPriceRanges. */ +export type ProductPriceRangeConnection = { + __typename?: 'ProductPriceRangeConnection' + /** A list of edges. */ + edges: Array<ProductPriceRangeEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one ProductPriceRange and a cursor during pagination. */ +export type ProductPriceRangeEdge = { + __typename?: 'ProductPriceRangeEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ProductPriceRangeEdge. */ + node: ProductPriceRange +} + +/** The set of valid sort keys for the Product query. */ +export enum ProductSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `product_type` value. */ + ProductType = 'PRODUCT_TYPE', + /** Sort by the `vendor` value. */ + Vendor = 'VENDOR', + /** Sort by the `updated_at` value. */ + UpdatedAt = 'UPDATED_AT', + /** Sort by the `created_at` value. */ + CreatedAt = 'CREATED_AT', + /** Sort by the `best_selling` value. */ + BestSelling = 'BEST_SELLING', + /** Sort by the `price` value. */ + Price = 'PRICE', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariant = Node & + HasMetafields & { + __typename?: 'ProductVariant' + /** + * Indicates if the product variant is in stock. + * @deprecated Use `availableForSale` instead + */ + available?: Maybe<Scalars['Boolean']> + /** Indicates if the product variant is available for sale. */ + availableForSale: Scalars['Boolean'] + /** + * The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPrice` is higher than `price`. + * @deprecated Use `compareAtPriceV2` instead + */ + compareAtPrice?: Maybe<Scalars['Money']> + /** The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPriceV2` is higher than `priceV2`. */ + compareAtPriceV2?: Maybe<MoneyV2> + /** Whether a product is out of stock but still available for purchase (used for backorders). */ + currentlyNotInStock: Scalars['Boolean'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** Image associated with the product variant. This field falls back to the product image if no image is available. */ + image?: Maybe<Image> + /** The metafield associated with the resource. */ + metafield?: Maybe<Metafield> + /** A paginated list of metafields associated with the resource. */ + metafields: MetafieldConnection + /** List of prices and compare-at prices in the presentment currencies for this shop. */ + presentmentPrices: ProductVariantPricePairConnection + /** List of unit prices in the presentment currencies for this shop. */ + presentmentUnitPrices: MoneyV2Connection + /** + * The product variant’s price. + * @deprecated Use `priceV2` instead + */ + price: Scalars['Money'] + /** The product variant’s price. */ + priceV2: MoneyV2 + /** The product object that the product variant belongs to. */ + product: Product + /** The total sellable quantity of the variant for online sales channels. */ + quantityAvailable?: Maybe<Scalars['Int']> + /** Whether a customer needs to provide a shipping address when placing an order for the product variant. */ + requiresShipping: Scalars['Boolean'] + /** List of product options applied to the variant. */ + selectedOptions: Array<SelectedOption> + /** The SKU (stock keeping unit) associated with the variant. */ + sku?: Maybe<Scalars['String']> + /** The product variant’s title. */ + title: Scalars['String'] + /** The unit price value for the variant based on the variant's measurement. */ + unitPrice?: Maybe<MoneyV2> + /** The unit price measurement for the variant. */ + unitPriceMeasurement?: Maybe<UnitPriceMeasurement> + /** The weight of the product variant in the unit system specified with `weight_unit`. */ + weight?: Maybe<Scalars['Float']> + /** Unit of measurement for weight. */ + weightUnit: WeightUnit + } + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantImageArgs = { + maxWidth?: Maybe<Scalars['Int']> + maxHeight?: Maybe<Scalars['Int']> + crop?: Maybe<CropRegion> + scale?: Maybe<Scalars['Int']> +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantMetafieldArgs = { + namespace: Scalars['String'] + key: Scalars['String'] +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantMetafieldsArgs = { + namespace?: Maybe<Scalars['String']> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantPresentmentPricesArgs = { + presentmentCurrencies?: Maybe<Array<CurrencyCode>> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** A product variant represents a different version of a product, such as differing sizes or differing colors. */ +export type ProductVariantPresentmentUnitPricesArgs = { + presentmentCurrencies?: Maybe<Array<CurrencyCode>> + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> +} + +/** An auto-generated type for paginating through multiple ProductVariants. */ +export type ProductVariantConnection = { + __typename?: 'ProductVariantConnection' + /** A list of edges. */ + edges: Array<ProductVariantEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one ProductVariant and a cursor during pagination. */ +export type ProductVariantEdge = { + __typename?: 'ProductVariantEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ProductVariantEdge. */ + node: ProductVariant +} + +/** The compare-at price and price of a variant sharing a currency. */ +export type ProductVariantPricePair = { + __typename?: 'ProductVariantPricePair' + /** The compare-at price of the variant with associated currency. */ + compareAtPrice?: Maybe<MoneyV2> + /** The price of the variant with associated currency. */ + price: MoneyV2 +} + +/** An auto-generated type for paginating through multiple ProductVariantPricePairs. */ +export type ProductVariantPricePairConnection = { + __typename?: 'ProductVariantPricePairConnection' + /** A list of edges. */ + edges: Array<ProductVariantPricePairEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one ProductVariantPricePair and a cursor during pagination. */ +export type ProductVariantPricePairEdge = { + __typename?: 'ProductVariantPricePairEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of ProductVariantPricePairEdge. */ + node: ProductVariantPricePair +} + +/** The set of valid sort keys for the ProductVariant query. */ +export enum ProductVariantSortKeys { + /** Sort by the `title` value. */ + Title = 'TITLE', + /** Sort by the `sku` value. */ + Sku = 'SKU', + /** Sort by the `position` value. */ + Position = 'POSITION', + /** Sort by the `id` value. */ + Id = 'ID', + /** + * During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + * results by relevance to the search term(s). When no search query is specified, this sort key is not + * deterministic and should not be used. + */ + Relevance = 'RELEVANCE', +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRoot = { + __typename?: 'QueryRoot' + /** List of the shop's articles. */ + articles: ArticleConnection + /** Find a blog by its handle. */ + blogByHandle?: Maybe<Blog> + /** List of the shop's blogs. */ + blogs: BlogConnection + /** Find a collection by its handle. */ + collectionByHandle?: Maybe<Collection> + /** List of the shop’s collections. */ + collections: CollectionConnection + /** Find a customer by its access token. */ + customer?: Maybe<Customer> + node?: Maybe<Node> + nodes: Array<Maybe<Node>> + /** Find a page by its handle. */ + pageByHandle?: Maybe<Page> + /** List of the shop's pages. */ + pages: PageConnection + /** Find a product by its handle. */ + productByHandle?: Maybe<Product> + /** + * Find recommended products related to a given `product_id`. + * To learn more about how recommendations are generated, see + * [*Showing product recommendations on product pages*](https://help.shopify.com/themes/development/recommended-products). + */ + productRecommendations?: Maybe<Array<Product>> + /** + * Tags added to products. + * Additional access scope required: unauthenticated_read_product_tags. + */ + productTags: StringConnection + /** List of product types for the shop's products that are published to your app. */ + productTypes: StringConnection + /** List of the shop’s products. */ + products: ProductConnection + /** The list of public Storefront API versions, including supported, release candidate and unstable versions. */ + publicApiVersions: Array<ApiVersion> + /** The shop associated with the storefront access token. */ + shop: Shop +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootArticlesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ArticleSortKeys> + query?: Maybe<Scalars['String']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootBlogByHandleArgs = { + handle: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootBlogsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<BlogSortKeys> + query?: Maybe<Scalars['String']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootCollectionByHandleArgs = { + handle: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootCollectionsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<CollectionSortKeys> + query?: Maybe<Scalars['String']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootCustomerArgs = { + customerAccessToken: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootNodeArgs = { + id: Scalars['ID'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootNodesArgs = { + ids: Array<Scalars['ID']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootPageByHandleArgs = { + handle: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootPagesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<PageSortKeys> + query?: Maybe<Scalars['String']> +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductByHandleArgs = { + handle: Scalars['String'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductRecommendationsArgs = { + productId: Scalars['ID'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductTagsArgs = { + first: Scalars['Int'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductTypesArgs = { + first: Scalars['Int'] +} + +/** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */ +export type QueryRootProductsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductSortKeys> + query?: Maybe<Scalars['String']> +} + +/** SEO information. */ +export type Seo = { + __typename?: 'SEO' + /** The meta description. */ + description?: Maybe<Scalars['String']> + /** The SEO title. */ + title?: Maybe<Scalars['String']> +} + +/** + * Script discount applications capture the intentions of a discount that + * was created by a Shopify Script. + */ +export type ScriptDiscountApplication = DiscountApplication & { + __typename?: 'ScriptDiscountApplication' + /** The method by which the discount's value is allocated to its entitled items. */ + allocationMethod: DiscountApplicationAllocationMethod + /** + * The description of the application as defined by the Script. + * @deprecated Use `title` instead + */ + description: Scalars['String'] + /** Which lines of targetType that the discount is allocated over. */ + targetSelection: DiscountApplicationTargetSelection + /** The type of line that the discount is applicable towards. */ + targetType: DiscountApplicationTargetType + /** The title of the application as defined by the Script. */ + title: Scalars['String'] + /** The value of the discount application. */ + value: PricingValue +} + +/** + * Properties used by customers to select a product variant. + * Products can have multiple options, like different sizes or colors. + */ +export type SelectedOption = { + __typename?: 'SelectedOption' + /** The product option’s name. */ + name: Scalars['String'] + /** The product option’s value. */ + value: Scalars['String'] +} + +/** Specifies the input fields required for a selected option. */ +export type SelectedOptionInput = { + /** The product option’s name. */ + name: Scalars['String'] + /** The product option’s value. */ + value: Scalars['String'] +} + +/** A shipping rate to be applied to a checkout. */ +export type ShippingRate = { + __typename?: 'ShippingRate' + /** Human-readable unique identifier for this shipping rate. */ + handle: Scalars['String'] + /** + * Price of this shipping rate. + * @deprecated Use `priceV2` instead + */ + price: Scalars['Money'] + /** Price of this shipping rate. */ + priceV2: MoneyV2 + /** Title of this shipping rate. */ + title: Scalars['String'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type Shop = { + __typename?: 'Shop' + /** + * List of the shop' articles. + * @deprecated Use `QueryRoot.articles` instead. + */ + articles: ArticleConnection + /** + * List of the shop' blogs. + * @deprecated Use `QueryRoot.blogs` instead. + */ + blogs: BlogConnection + /** + * Find a collection by its handle. + * @deprecated Use `QueryRoot.collectionByHandle` instead. + */ + collectionByHandle?: Maybe<Collection> + /** + * List of the shop’s collections. + * @deprecated Use `QueryRoot.collections` instead. + */ + collections: CollectionConnection + /** + * The three-letter code for the currency that the shop accepts. + * @deprecated Use `paymentSettings` instead + */ + currencyCode: CurrencyCode + /** A description of the shop. */ + description?: Maybe<Scalars['String']> + /** A string representing the way currency is formatted when the currency isn’t specified. */ + moneyFormat: Scalars['String'] + /** The shop’s name. */ + name: Scalars['String'] + /** Settings related to payments. */ + paymentSettings: PaymentSettings + /** The shop’s primary domain. */ + primaryDomain: Domain + /** The shop’s privacy policy. */ + privacyPolicy?: Maybe<ShopPolicy> + /** + * Find a product by its handle. + * @deprecated Use `QueryRoot.productByHandle` instead. + */ + productByHandle?: Maybe<Product> + /** + * A list of tags that have been added to products. + * Additional access scope required: unauthenticated_read_product_tags. + * @deprecated Use `QueryRoot.productTags` instead. + */ + productTags: StringConnection + /** + * List of the shop’s product types. + * @deprecated Use `QueryRoot.productTypes` instead. + */ + productTypes: StringConnection + /** + * List of the shop’s products. + * @deprecated Use `QueryRoot.products` instead. + */ + products: ProductConnection + /** The shop’s refund policy. */ + refundPolicy?: Maybe<ShopPolicy> + /** The shop’s shipping policy. */ + shippingPolicy?: Maybe<ShopPolicy> + /** Countries that the shop ships to. */ + shipsToCountries: Array<CountryCode> + /** + * The shop’s Shopify Payments account id. + * @deprecated Use `paymentSettings` instead + */ + shopifyPaymentsAccountId?: Maybe<Scalars['String']> + /** The shop’s terms of service. */ + termsOfService?: Maybe<ShopPolicy> +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopArticlesArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ArticleSortKeys> + query?: Maybe<Scalars['String']> +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopBlogsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<BlogSortKeys> + query?: Maybe<Scalars['String']> +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopCollectionByHandleArgs = { + handle: Scalars['String'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopCollectionsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<CollectionSortKeys> + query?: Maybe<Scalars['String']> +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopProductByHandleArgs = { + handle: Scalars['String'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopProductTagsArgs = { + first: Scalars['Int'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopProductTypesArgs = { + first: Scalars['Int'] +} + +/** Shop represents a collection of the general settings and information about the shop. */ +export type ShopProductsArgs = { + first?: Maybe<Scalars['Int']> + after?: Maybe<Scalars['String']> + last?: Maybe<Scalars['Int']> + before?: Maybe<Scalars['String']> + reverse?: Maybe<Scalars['Boolean']> + sortKey?: Maybe<ProductSortKeys> + query?: Maybe<Scalars['String']> +} + +/** Policy that a merchant has configured for their store, such as their refund or privacy policy. */ +export type ShopPolicy = Node & { + __typename?: 'ShopPolicy' + /** Policy text, maximum size of 64kb. */ + body: Scalars['String'] + /** Policy’s handle. */ + handle: Scalars['String'] + /** Globally unique identifier. */ + id: Scalars['ID'] + /** Policy’s title. */ + title: Scalars['String'] + /** Public URL to the policy. */ + url: Scalars['URL'] +} + +/** An auto-generated type for paginating through multiple Strings. */ +export type StringConnection = { + __typename?: 'StringConnection' + /** A list of edges. */ + edges: Array<StringEdge> + /** Information to aid in pagination. */ + pageInfo: PageInfo +} + +/** An auto-generated type which holds one String and a cursor during pagination. */ +export type StringEdge = { + __typename?: 'StringEdge' + /** A cursor for use in pagination. */ + cursor: Scalars['String'] + /** The item at the end of StringEdge. */ + node: Scalars['String'] +} + +/** + * Specifies the fields required to complete a checkout with + * a tokenized payment. + */ +export type TokenizedPaymentInput = { + /** The amount of the payment. */ + amount: Scalars['Money'] + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** The type of payment token. */ + type: Scalars['String'] + /** A simple string or JSON containing the required payment data for the tokenized payment. */ + paymentData: Scalars['String'] + /** Executes the payment in test mode if possible. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> + /** Public Hash Key used for AndroidPay payments only. */ + identifier?: Maybe<Scalars['String']> +} + +/** + * Specifies the fields required to complete a checkout with + * a tokenized payment. + */ +export type TokenizedPaymentInputV2 = { + /** The amount and currency of the payment. */ + paymentAmount: MoneyInput + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** A simple string or JSON containing the required payment data for the tokenized payment. */ + paymentData: Scalars['String'] + /** Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> + /** Public Hash Key used for AndroidPay payments only. */ + identifier?: Maybe<Scalars['String']> + /** The type of payment token. */ + type: Scalars['String'] +} + +/** + * Specifies the fields required to complete a checkout with + * a tokenized payment. + */ +export type TokenizedPaymentInputV3 = { + /** The amount and currency of the payment. */ + paymentAmount: MoneyInput + /** A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. */ + idempotencyKey: Scalars['String'] + /** The billing address for the payment. */ + billingAddress: MailingAddressInput + /** A simple string or JSON containing the required payment data for the tokenized payment. */ + paymentData: Scalars['String'] + /** Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`. */ + test?: Maybe<Scalars['Boolean']> + /** Public Hash Key used for AndroidPay payments only. */ + identifier?: Maybe<Scalars['String']> + /** The type of payment token. */ + type: PaymentTokenType +} + +/** An object representing exchange of money for a product or service. */ +export type Transaction = { + __typename?: 'Transaction' + /** + * The amount of money that the transaction was for. + * @deprecated Use `amountV2` instead + */ + amount: Scalars['Money'] + /** The amount of money that the transaction was for. */ + amountV2: MoneyV2 + /** The kind of the transaction. */ + kind: TransactionKind + /** + * The status of the transaction. + * @deprecated Use `statusV2` instead + */ + status: TransactionStatus + /** The status of the transaction. */ + statusV2?: Maybe<TransactionStatus> + /** Whether the transaction was done in test mode or not. */ + test: Scalars['Boolean'] +} + +export enum TransactionKind { + Sale = 'SALE', + Capture = 'CAPTURE', + Authorization = 'AUTHORIZATION', + EmvAuthorization = 'EMV_AUTHORIZATION', + Change = 'CHANGE', +} + +export enum TransactionStatus { + Pending = 'PENDING', + Success = 'SUCCESS', + Failure = 'FAILURE', + Error = 'ERROR', +} + +/** The measurement used to calculate a unit price for a product variant (e.g. $9.99 / 100ml). */ +export type UnitPriceMeasurement = { + __typename?: 'UnitPriceMeasurement' + /** The type of unit of measurement for the unit price measurement. */ + measuredType?: Maybe<UnitPriceMeasurementMeasuredType> + /** The quantity unit for the unit price measurement. */ + quantityUnit?: Maybe<UnitPriceMeasurementMeasuredUnit> + /** The quantity value for the unit price measurement. */ + quantityValue: Scalars['Float'] + /** The reference unit for the unit price measurement. */ + referenceUnit?: Maybe<UnitPriceMeasurementMeasuredUnit> + /** The reference value for the unit price measurement. */ + referenceValue: Scalars['Int'] +} + +/** The accepted types of unit of measurement. */ +export enum UnitPriceMeasurementMeasuredType { + /** Unit of measurements representing volumes. */ + Volume = 'VOLUME', + /** Unit of measurements representing weights. */ + Weight = 'WEIGHT', + /** Unit of measurements representing lengths. */ + Length = 'LENGTH', + /** Unit of measurements representing areas. */ + Area = 'AREA', +} + +/** The valid units of measurement for a unit price measurement. */ +export enum UnitPriceMeasurementMeasuredUnit { + /** 1000 milliliters equals 1 liter. */ + Ml = 'ML', + /** 100 centiliters equals 1 liter. */ + Cl = 'CL', + /** Metric system unit of volume. */ + L = 'L', + /** 1 cubic meter equals 1000 liters. */ + M3 = 'M3', + /** 1000 milligrams equals 1 gram. */ + Mg = 'MG', + /** Metric system unit of weight. */ + G = 'G', + /** 1 kilogram equals 1000 grams. */ + Kg = 'KG', + /** 1000 millimeters equals 1 meter. */ + Mm = 'MM', + /** 100 centimeters equals 1 meter. */ + Cm = 'CM', + /** Metric system unit of length. */ + M = 'M', + /** Metric system unit of area. */ + M2 = 'M2', +} + +/** Represents an error in the input of a mutation. */ +export type UserError = DisplayableError & { + __typename?: 'UserError' + /** Path to the input field which caused the error. */ + field?: Maybe<Array<Scalars['String']>> + /** The error message. */ + message: Scalars['String'] +} + +/** Represents a Shopify hosted video. */ +export type Video = Node & + Media & { + __typename?: 'Video' + /** A word or phrase to share the nature or contents of a media. */ + alt?: Maybe<Scalars['String']> + /** Globally unique identifier. */ + id: Scalars['ID'] + /** The media content type. */ + mediaContentType: MediaContentType + /** The preview image for the media. */ + previewImage?: Maybe<Image> + /** The sources for a video. */ + sources: Array<VideoSource> + } + +/** Represents a source for a Shopify hosted video. */ +export type VideoSource = { + __typename?: 'VideoSource' + /** The format of the video source. */ + format: Scalars['String'] + /** The height of the video. */ + height: Scalars['Int'] + /** The video MIME type. */ + mimeType: Scalars['String'] + /** The URL of the video. */ + url: Scalars['String'] + /** The width of the video. */ + width: Scalars['Int'] +} + +/** Units of measurement for weight. */ +export enum WeightUnit { + /** 1 kilogram equals 1000 grams. */ + Kilograms = 'KILOGRAMS', + /** Metric system unit of mass. */ + Grams = 'GRAMS', + /** 1 pound equals 16 ounces. */ + Pounds = 'POUNDS', + /** Imperial system unit of mass. */ + Ounces = 'OUNCES', +} + +export type Unnamed_1_QueryVariables = Exact<{ + first: Scalars['Int'] +}> + +export type Unnamed_1_Query = { __typename?: 'QueryRoot' } & { + pages: { __typename?: 'PageConnection' } & { + edges: Array< + { __typename?: 'PageEdge' } & { + node: { __typename?: 'Page' } & Pick< + Page, + 'id' | 'title' | 'handle' | 'body' | 'bodySummary' | 'url' + > + } + > + } +} diff --git a/framework/swell/schema.graphql b/framework/swell/schema.graphql new file mode 100644 index 00000000..822e6007 --- /dev/null +++ b/framework/swell/schema.graphql @@ -0,0 +1,9631 @@ +schema { + query: QueryRoot + mutation: Mutation +} + +""" +Marks an element of a GraphQL schema as having restricted access. +""" +directive @accessRestricted( + """ + Explains the reason around this restriction + """ + reason: String = null +) on FIELD_DEFINITION | OBJECT + +""" +A version of the API. +""" +type ApiVersion { + """ + The human-readable name of the version. + """ + displayName: String! + + """ + The unique identifier of an ApiVersion. All supported API versions have a date-based (YYYY-MM) or `unstable` handle. + """ + handle: String! + + """ + Whether the version is supported by Shopify. + """ + supported: Boolean! +} + +""" +Details about the gift card used on the checkout. +""" +type AppliedGiftCard implements Node { + """ + The amount that was taken from the gift card by applying it. + """ + amountUsed: Money! @deprecated(reason: "Use `amountUsedV2` instead") + + """ + The amount that was taken from the gift card by applying it. + """ + amountUsedV2: MoneyV2! + + """ + The amount left on the gift card. + """ + balance: Money! @deprecated(reason: "Use `balanceV2` instead") + + """ + The amount left on the gift card. + """ + balanceV2: MoneyV2! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The last characters of the gift card. + """ + lastCharacters: String! + + """ + The amount that was applied to the checkout in its currency. + """ + presentmentAmountUsed: MoneyV2! +} + +""" +An article in an online store blog. +""" +type Article implements Node { + """ + The article's author. + """ + author: ArticleAuthor! @deprecated(reason: "Use `authorV2` instead") + + """ + The article's author. + """ + authorV2: ArticleAuthor + + """ + The blog that the article belongs to. + """ + blog: Blog! + + """ + List of comments posted on the article. + """ + comments( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): CommentConnection! + + """ + Stripped content of the article, single line with HTML tags removed. + """ + content( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String! + + """ + The content of the article, complete with HTML formatting. + """ + contentHtml: HTML! + + """ + Stripped excerpt of the article, single line with HTML tags removed. + """ + excerpt( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String + + """ + The excerpt of the article, complete with HTML formatting. + """ + excerptHtml: HTML + + """ + A human-friendly unique string for the Article automatically generated from its title. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The image associated with the article. + """ + image( + """ + Image width in pixels between 1 and 2048. This argument is deprecated: Use `maxWidth` on `Image.transformedSrc` instead. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 2048. This argument is deprecated: Use `maxHeight` on `Image.transformedSrc` instead. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. This argument is deprecated: Use `crop` on `Image.transformedSrc` instead. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. This argument is deprecated: Use `scale` on `Image.transformedSrc` instead. + """ + scale: Int = 1 + ): Image + + """ + The date and time when the article was published. + """ + publishedAt: DateTime! + + """ + The article’s SEO information. + """ + seo: SEO + + """ + A categorization that a article can be tagged with. + """ + tags: [String!]! + + """ + The article’s name. + """ + title: String! + + """ + The url pointing to the article accessible from the web. + """ + url: URL! +} + +""" +The author of an article. +""" +type ArticleAuthor { + """ + The author's bio. + """ + bio: String + + """ + The author’s email. + """ + email: String! + + """ + The author's first name. + """ + firstName: String! + + """ + The author's last name. + """ + lastName: String! + + """ + The author's full name. + """ + name: String! +} + +""" +An auto-generated type for paginating through multiple Articles. +""" +type ArticleConnection { + """ + A list of edges. + """ + edges: [ArticleEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Article and a cursor during pagination. +""" +type ArticleEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ArticleEdge. + """ + node: Article! +} + +""" +The set of valid sort keys for the Article query. +""" +enum ArticleSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `blog_title` value. + """ + BLOG_TITLE + + """ + Sort by the `author` value. + """ + AUTHOR + + """ + Sort by the `updated_at` value. + """ + UPDATED_AT + + """ + Sort by the `published_at` value. + """ + PUBLISHED_AT + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +Represents a generic custom attribute. +""" +type Attribute { + """ + Key or name of the attribute. + """ + key: String! + + """ + Value of the attribute. + """ + value: String +} + +""" +Specifies the input fields required for an attribute. +""" +input AttributeInput { + """ + Key or name of the attribute. + """ + key: String! + + """ + Value of the attribute. + """ + value: String! +} + +""" +Automatic discount applications capture the intentions of a discount that was automatically applied. +""" +type AutomaticDiscountApplication implements DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The title of the application. + """ + title: String! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +A collection of available shipping rates for a checkout. +""" +type AvailableShippingRates { + """ + Whether or not the shipping rates are ready. + The `shippingRates` field is `null` when this value is `false`. + This field should be polled until its value becomes `true`. + """ + ready: Boolean! + + """ + The fetched shipping rates. `null` until the `ready` field is `true`. + """ + shippingRates: [ShippingRate!] +} + +""" +An online store blog. +""" +type Blog implements Node { + """ + Find an article by its handle. + """ + articleByHandle( + """ + The handle of the article. + """ + handle: String! + ): Article + + """ + List of the blog's articles. + """ + articles( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ArticleSortKeys = ID + + """ + Supported filter parameters: + - `author` + - `blog_title` + - `created_at` + - `tag` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ArticleConnection! + + """ + The authors who have contributed to the blog. + """ + authors: [ArticleAuthor!]! + + """ + A human-friendly unique string for the Blog automatically generated from its title. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The blog's SEO information. + """ + seo: SEO + + """ + The blogs’s title. + """ + title: String! + + """ + The url pointing to the blog accessible from the web. + """ + url: URL! +} + +""" +An auto-generated type for paginating through multiple Blogs. +""" +type BlogConnection { + """ + A list of edges. + """ + edges: [BlogEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Blog and a cursor during pagination. +""" +type BlogEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of BlogEdge. + """ + node: Blog! +} + +""" +The set of valid sort keys for the Blog query. +""" +enum BlogSortKeys { + """ + Sort by the `handle` value. + """ + HANDLE + + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +Card brand, such as Visa or Mastercard, which can be used for payments. +""" +enum CardBrand { + """ + Visa + """ + VISA + + """ + Mastercard + """ + MASTERCARD + + """ + Discover + """ + DISCOVER + + """ + American Express + """ + AMERICAN_EXPRESS + + """ + Diners Club + """ + DINERS_CLUB + + """ + JCB + """ + JCB +} + +""" +A container for all the information required to checkout items and pay. +""" +type Checkout implements Node { + """ + The gift cards used on the checkout. + """ + appliedGiftCards: [AppliedGiftCard!]! + + """ + The available shipping rates for this Checkout. + Should only be used when checkout `requiresShipping` is `true` and + the shipping address is valid. + """ + availableShippingRates: AvailableShippingRates + + """ + The date and time when the checkout was completed. + """ + completedAt: DateTime + + """ + The date and time when the checkout was created. + """ + createdAt: DateTime! + + """ + The currency code for the Checkout. + """ + currencyCode: CurrencyCode! + + """ + A list of extra information that is added to the checkout. + """ + customAttributes: [Attribute!]! + + """ + The customer associated with the checkout. + """ + customer: Customer + @deprecated( + reason: "This field will always return null. If you have an authentication token for the customer, you can use the `customer` field on the query root to retrieve it." + ) + + """ + Discounts that have been applied on the checkout. + """ + discountApplications( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): DiscountApplicationConnection! + + """ + The email attached to this checkout. + """ + email: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + A list of line item objects, each one containing information about an item in the checkout. + """ + lineItems( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): CheckoutLineItemConnection! + + """ + The sum of all the prices of all the items in the checkout. Duties, taxes, shipping and discounts excluded. + """ + lineItemsSubtotalPrice: MoneyV2! + + """ + The note associated with the checkout. + """ + note: String + + """ + The resulting order from a paid checkout. + """ + order: Order + + """ + The Order Status Page for this Checkout, null when checkout is not completed. + """ + orderStatusUrl: URL + + """ + The amount left to be paid. This is equal to the cost of the line items, taxes and shipping minus discounts and gift cards. + """ + paymentDue: Money! @deprecated(reason: "Use `paymentDueV2` instead") + + """ + The amount left to be paid. This is equal to the cost of the line items, duties, taxes and shipping minus discounts and gift cards. + """ + paymentDueV2: MoneyV2! + + """ + Whether or not the Checkout is ready and can be completed. Checkouts may + have asynchronous operations that can take time to finish. If you want + to complete a checkout or ensure all the fields are populated and up to + date, polling is required until the value is true. + """ + ready: Boolean! + + """ + States whether or not the fulfillment requires shipping. + """ + requiresShipping: Boolean! + + """ + The shipping address to where the line items will be shipped. + """ + shippingAddress: MailingAddress + + """ + The discounts that have been allocated onto the shipping line by discount applications. + """ + shippingDiscountAllocations: [DiscountAllocation!]! + + """ + Once a shipping rate is selected by the customer it is transitioned to a `shipping_line` object. + """ + shippingLine: ShippingRate + + """ + Price of the checkout before shipping and taxes. + """ + subtotalPrice: Money! @deprecated(reason: "Use `subtotalPriceV2` instead") + + """ + Price of the checkout before duties, shipping and taxes. + """ + subtotalPriceV2: MoneyV2! + + """ + Specifies if the Checkout is tax exempt. + """ + taxExempt: Boolean! + + """ + Specifies if taxes are included in the line item and shipping line prices. + """ + taxesIncluded: Boolean! + + """ + The sum of all the prices of all the items in the checkout, taxes and discounts included. + """ + totalPrice: Money! @deprecated(reason: "Use `totalPriceV2` instead") + + """ + The sum of all the prices of all the items in the checkout, duties, taxes and discounts included. + """ + totalPriceV2: MoneyV2! + + """ + The sum of all the taxes applied to the line items and shipping lines in the checkout. + """ + totalTax: Money! @deprecated(reason: "Use `totalTaxV2` instead") + + """ + The sum of all the taxes applied to the line items and shipping lines in the checkout. + """ + totalTaxV2: MoneyV2! + + """ + The date and time when the checkout was last updated. + """ + updatedAt: DateTime! + + """ + The url pointing to the checkout accessible from the web. + """ + webUrl: URL! +} + +""" +Specifies the fields required to update a checkout's attributes. +""" +input CheckoutAttributesUpdateInput { + """ + The text of an optional note that a shop owner can attach to the checkout. + """ + note: String + + """ + A list of extra information that is added to the checkout. + """ + customAttributes: [AttributeInput!] + + """ + Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + The required attributes are city, province, and country. + Full validation of the addresses is still done at complete time. + """ + allowPartialAddresses: Boolean +} + +""" +Return type for `checkoutAttributesUpdate` mutation. +""" +type CheckoutAttributesUpdatePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Specifies the fields required to update a checkout's attributes. +""" +input CheckoutAttributesUpdateV2Input { + """ + The text of an optional note that a shop owner can attach to the checkout. + """ + note: String + + """ + A list of extra information that is added to the checkout. + """ + customAttributes: [AttributeInput!] + + """ + Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + The required attributes are city, province, and country. + Full validation of the addresses is still done at complete time. + """ + allowPartialAddresses: Boolean +} + +""" +Return type for `checkoutAttributesUpdateV2` mutation. +""" +type CheckoutAttributesUpdateV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteFree` mutation. +""" +type CheckoutCompleteFreePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithCreditCard` mutation. +""" +type CheckoutCompleteWithCreditCardPayload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithCreditCardV2` mutation. +""" +type CheckoutCompleteWithCreditCardV2Payload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithTokenizedPayment` mutation. +""" +type CheckoutCompleteWithTokenizedPaymentPayload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithTokenizedPaymentV2` mutation. +""" +type CheckoutCompleteWithTokenizedPaymentV2Payload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCompleteWithTokenizedPaymentV3` mutation. +""" +type CheckoutCompleteWithTokenizedPaymentV3Payload { + """ + The checkout on which the payment was applied. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + A representation of the attempted payment. + """ + payment: Payment + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Specifies the fields required to create a checkout. +""" +input CheckoutCreateInput { + """ + The email with which the customer wants to checkout. + """ + email: String + + """ + A list of line item objects, each one containing information about an item in the checkout. + """ + lineItems: [CheckoutLineItemInput!] + + """ + The shipping address to where the line items will be shipped. + """ + shippingAddress: MailingAddressInput + + """ + The text of an optional note that a shop owner can attach to the checkout. + """ + note: String + + """ + A list of extra information that is added to the checkout. + """ + customAttributes: [AttributeInput!] + + """ + Allows setting partial addresses on a Checkout, skipping the full validation of attributes. + The required attributes are city, province, and country. + Full validation of addresses is still done at complete time. + """ + allowPartialAddresses: Boolean + + """ + The three-letter currency code of one of the shop's enabled presentment currencies. + Including this field creates a checkout in the specified currency. By default, new + checkouts are created in the shop's primary currency. + """ + presentmentCurrencyCode: CurrencyCode +} + +""" +Return type for `checkoutCreate` mutation. +""" +type CheckoutCreatePayload { + """ + The new checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCustomerAssociate` mutation. +""" +type CheckoutCustomerAssociatePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + The associated customer object. + """ + customer: Customer + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! +} + +""" +Return type for `checkoutCustomerAssociateV2` mutation. +""" +type CheckoutCustomerAssociateV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + The associated customer object. + """ + customer: Customer + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCustomerDisassociate` mutation. +""" +type CheckoutCustomerDisassociatePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutCustomerDisassociateV2` mutation. +""" +type CheckoutCustomerDisassociateV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutDiscountCodeApply` mutation. +""" +type CheckoutDiscountCodeApplyPayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutDiscountCodeApplyV2` mutation. +""" +type CheckoutDiscountCodeApplyV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutDiscountCodeRemove` mutation. +""" +type CheckoutDiscountCodeRemovePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutEmailUpdate` mutation. +""" +type CheckoutEmailUpdatePayload { + """ + The checkout object with the updated email. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutEmailUpdateV2` mutation. +""" +type CheckoutEmailUpdateV2Payload { + """ + The checkout object with the updated email. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Possible error codes that could be returned by CheckoutUserError. +""" +enum CheckoutErrorCode { + """ + Input value is blank. + """ + BLANK + + """ + Input value is invalid. + """ + INVALID + + """ + Input value is too long. + """ + TOO_LONG + + """ + Input value is not present. + """ + PRESENT + + """ + Input value should be less than maximum allowed value. + """ + LESS_THAN + + """ + Input value should be greater than or equal to minimum allowed value. + """ + GREATER_THAN_OR_EQUAL_TO + + """ + Input value should be less or equal to maximum allowed value. + """ + LESS_THAN_OR_EQUAL_TO + + """ + Checkout is already completed. + """ + ALREADY_COMPLETED + + """ + Checkout is locked. + """ + LOCKED + + """ + Input value is not supported. + """ + NOT_SUPPORTED + + """ + Input email contains an invalid domain name. + """ + BAD_DOMAIN + + """ + Input Zip is invalid for country provided. + """ + INVALID_FOR_COUNTRY + + """ + Input Zip is invalid for country and province provided. + """ + INVALID_FOR_COUNTRY_AND_PROVINCE + + """ + Invalid state in country. + """ + INVALID_STATE_IN_COUNTRY + + """ + Invalid province in country. + """ + INVALID_PROVINCE_IN_COUNTRY + + """ + Invalid region in country. + """ + INVALID_REGION_IN_COUNTRY + + """ + Shipping rate expired. + """ + SHIPPING_RATE_EXPIRED + + """ + Gift card cannot be applied to a checkout that contains a gift card. + """ + GIFT_CARD_UNUSABLE + + """ + Gift card is disabled. + """ + GIFT_CARD_DISABLED + + """ + Gift card code is invalid. + """ + GIFT_CARD_CODE_INVALID + + """ + Gift card has already been applied. + """ + GIFT_CARD_ALREADY_APPLIED + + """ + Gift card currency does not match checkout currency. + """ + GIFT_CARD_CURRENCY_MISMATCH + + """ + Gift card is expired. + """ + GIFT_CARD_EXPIRED + + """ + Gift card has no funds left. + """ + GIFT_CARD_DEPLETED + + """ + Gift card was not found. + """ + GIFT_CARD_NOT_FOUND + + """ + Cart does not meet discount requirements notice. + """ + CART_DOES_NOT_MEET_DISCOUNT_REQUIREMENTS_NOTICE + + """ + Discount expired. + """ + DISCOUNT_EXPIRED + + """ + Discount disabled. + """ + DISCOUNT_DISABLED + + """ + Discount limit reached. + """ + DISCOUNT_LIMIT_REACHED + + """ + Discount not found. + """ + DISCOUNT_NOT_FOUND + + """ + Customer already used once per customer discount notice. + """ + CUSTOMER_ALREADY_USED_ONCE_PER_CUSTOMER_DISCOUNT_NOTICE + + """ + Checkout is already completed. + """ + EMPTY + + """ + Not enough in stock. + """ + NOT_ENOUGH_IN_STOCK + + """ + Missing payment input. + """ + MISSING_PAYMENT_INPUT + + """ + The amount of the payment does not match the value to be paid. + """ + TOTAL_PRICE_MISMATCH + + """ + Line item was not found in checkout. + """ + LINE_ITEM_NOT_FOUND + + """ + Unable to apply discount. + """ + UNABLE_TO_APPLY + + """ + Discount already applied. + """ + DISCOUNT_ALREADY_APPLIED +} + +""" +Return type for `checkoutGiftCardApply` mutation. +""" +type CheckoutGiftCardApplyPayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutGiftCardRemove` mutation. +""" +type CheckoutGiftCardRemovePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutGiftCardRemoveV2` mutation. +""" +type CheckoutGiftCardRemoveV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutGiftCardsAppend` mutation. +""" +type CheckoutGiftCardsAppendPayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +A single line item in the checkout, grouped by variant and attributes. +""" +type CheckoutLineItem implements Node { + """ + Extra information in the form of an array of Key-Value pairs about the line item. + """ + customAttributes: [Attribute!]! + + """ + The discounts that have been allocated onto the checkout line item by discount applications. + """ + discountAllocations: [DiscountAllocation!]! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The quantity of the line item. + """ + quantity: Int! + + """ + Title of the line item. Defaults to the product's title. + """ + title: String! + + """ + Unit price of the line item. + """ + unitPrice: MoneyV2 + + """ + Product variant of the line item. + """ + variant: ProductVariant +} + +""" +An auto-generated type for paginating through multiple CheckoutLineItems. +""" +type CheckoutLineItemConnection { + """ + A list of edges. + """ + edges: [CheckoutLineItemEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one CheckoutLineItem and a cursor during pagination. +""" +type CheckoutLineItemEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of CheckoutLineItemEdge. + """ + node: CheckoutLineItem! +} + +""" +Specifies the input fields to create a line item on a checkout. +""" +input CheckoutLineItemInput { + """ + Extra information in the form of an array of Key-Value pairs about the line item. + """ + customAttributes: [AttributeInput!] + + """ + The quantity of the line item. + """ + quantity: Int! + + """ + The identifier of the product variant for the line item. + """ + variantId: ID! +} + +""" +Specifies the input fields to update a line item on the checkout. +""" +input CheckoutLineItemUpdateInput { + """ + The identifier of the line item. + """ + id: ID + + """ + The variant identifier of the line item. + """ + variantId: ID + + """ + The quantity of the line item. + """ + quantity: Int + + """ + Extra information in the form of an array of Key-Value pairs about the line item. + """ + customAttributes: [AttributeInput!] +} + +""" +Return type for `checkoutLineItemsAdd` mutation. +""" +type CheckoutLineItemsAddPayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutLineItemsRemove` mutation. +""" +type CheckoutLineItemsRemovePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutLineItemsReplace` mutation. +""" +type CheckoutLineItemsReplacePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [CheckoutUserError!]! +} + +""" +Return type for `checkoutLineItemsUpdate` mutation. +""" +type CheckoutLineItemsUpdatePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutShippingAddressUpdate` mutation. +""" +type CheckoutShippingAddressUpdatePayload { + """ + The updated checkout object. + """ + checkout: Checkout! + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutShippingAddressUpdateV2` mutation. +""" +type CheckoutShippingAddressUpdateV2Payload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Return type for `checkoutShippingLineUpdate` mutation. +""" +type CheckoutShippingLineUpdatePayload { + """ + The updated checkout object. + """ + checkout: Checkout + + """ + List of errors that occurred executing the mutation. + """ + checkoutUserErrors: [CheckoutUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `checkoutUserErrors` instead") +} + +""" +Represents an error that happens during execution of a checkout mutation. +""" +type CheckoutUserError implements DisplayableError { + """ + Error code to uniquely identify the error. + """ + code: CheckoutErrorCode + + """ + Path to the input field which caused the error. + """ + field: [String!] + + """ + The error message. + """ + message: String! +} + +""" +A collection represents a grouping of products that a shop owner can create to organize them or make their shops easier to browse. +""" +type Collection implements Node { + """ + Stripped description of the collection, single line with HTML tags removed. + """ + description( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String! + + """ + The description of the collection, complete with HTML formatting. + """ + descriptionHtml: HTML! + + """ + A human-friendly unique string for the collection automatically generated from its title. + Limit of 255 characters. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + Image associated with the collection. + """ + image( + """ + Image width in pixels between 1 and 2048. This argument is deprecated: Use `maxWidth` on `Image.transformedSrc` instead. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 2048. This argument is deprecated: Use `maxHeight` on `Image.transformedSrc` instead. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. This argument is deprecated: Use `crop` on `Image.transformedSrc` instead. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. This argument is deprecated: Use `scale` on `Image.transformedSrc` instead. + """ + scale: Int = 1 + ): Image + + """ + List of products in the collection. + """ + products( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductCollectionSortKeys = COLLECTION_DEFAULT + ): ProductConnection! + + """ + The collection’s name. Limit of 255 characters. + """ + title: String! + + """ + The date and time when the collection was last modified. + """ + updatedAt: DateTime! +} + +""" +An auto-generated type for paginating through multiple Collections. +""" +type CollectionConnection { + """ + A list of edges. + """ + edges: [CollectionEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Collection and a cursor during pagination. +""" +type CollectionEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of CollectionEdge. + """ + node: Collection! +} + +""" +The set of valid sort keys for the Collection query. +""" +enum CollectionSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `updated_at` value. + """ + UPDATED_AT + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +A comment on an article. +""" +type Comment implements Node { + """ + The comment’s author. + """ + author: CommentAuthor! + + """ + Stripped content of the comment, single line with HTML tags removed. + """ + content( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String! + + """ + The content of the comment, complete with HTML formatting. + """ + contentHtml: HTML! + + """ + Globally unique identifier. + """ + id: ID! +} + +""" +The author of a comment. +""" +type CommentAuthor { + """ + The author's email. + """ + email: String! + + """ + The author’s name. + """ + name: String! +} + +""" +An auto-generated type for paginating through multiple Comments. +""" +type CommentConnection { + """ + A list of edges. + """ + edges: [CommentEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Comment and a cursor during pagination. +""" +type CommentEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of CommentEdge. + """ + node: Comment! +} + +""" +ISO 3166-1 alpha-2 country codes with some differences. +""" +enum CountryCode { + """ + Afghanistan. + """ + AF + + """ + Åland Islands. + """ + AX + + """ + Albania. + """ + AL + + """ + Algeria. + """ + DZ + + """ + Andorra. + """ + AD + + """ + Angola. + """ + AO + + """ + Anguilla. + """ + AI + + """ + Antigua & Barbuda. + """ + AG + + """ + Argentina. + """ + AR + + """ + Armenia. + """ + AM + + """ + Aruba. + """ + AW + + """ + Australia. + """ + AU + + """ + Austria. + """ + AT + + """ + Azerbaijan. + """ + AZ + + """ + Bahamas. + """ + BS + + """ + Bahrain. + """ + BH + + """ + Bangladesh. + """ + BD + + """ + Barbados. + """ + BB + + """ + Belarus. + """ + BY + + """ + Belgium. + """ + BE + + """ + Belize. + """ + BZ + + """ + Benin. + """ + BJ + + """ + Bermuda. + """ + BM + + """ + Bhutan. + """ + BT + + """ + Bolivia. + """ + BO + + """ + Bosnia & Herzegovina. + """ + BA + + """ + Botswana. + """ + BW + + """ + Bouvet Island. + """ + BV + + """ + Brazil. + """ + BR + + """ + British Indian Ocean Territory. + """ + IO + + """ + Brunei. + """ + BN + + """ + Bulgaria. + """ + BG + + """ + Burkina Faso. + """ + BF + + """ + Burundi. + """ + BI + + """ + Cambodia. + """ + KH + + """ + Canada. + """ + CA + + """ + Cape Verde. + """ + CV + + """ + Caribbean Netherlands. + """ + BQ + + """ + Cayman Islands. + """ + KY + + """ + Central African Republic. + """ + CF + + """ + Chad. + """ + TD + + """ + Chile. + """ + CL + + """ + China. + """ + CN + + """ + Christmas Island. + """ + CX + + """ + Cocos (Keeling) Islands. + """ + CC + + """ + Colombia. + """ + CO + + """ + Comoros. + """ + KM + + """ + Congo - Brazzaville. + """ + CG + + """ + Congo - Kinshasa. + """ + CD + + """ + Cook Islands. + """ + CK + + """ + Costa Rica. + """ + CR + + """ + Croatia. + """ + HR + + """ + Cuba. + """ + CU + + """ + Curaçao. + """ + CW + + """ + Cyprus. + """ + CY + + """ + Czechia. + """ + CZ + + """ + Côte d’Ivoire. + """ + CI + + """ + Denmark. + """ + DK + + """ + Djibouti. + """ + DJ + + """ + Dominica. + """ + DM + + """ + Dominican Republic. + """ + DO + + """ + Ecuador. + """ + EC + + """ + Egypt. + """ + EG + + """ + El Salvador. + """ + SV + + """ + Equatorial Guinea. + """ + GQ + + """ + Eritrea. + """ + ER + + """ + Estonia. + """ + EE + + """ + Eswatini. + """ + SZ + + """ + Ethiopia. + """ + ET + + """ + Falkland Islands. + """ + FK + + """ + Faroe Islands. + """ + FO + + """ + Fiji. + """ + FJ + + """ + Finland. + """ + FI + + """ + France. + """ + FR + + """ + French Guiana. + """ + GF + + """ + French Polynesia. + """ + PF + + """ + French Southern Territories. + """ + TF + + """ + Gabon. + """ + GA + + """ + Gambia. + """ + GM + + """ + Georgia. + """ + GE + + """ + Germany. + """ + DE + + """ + Ghana. + """ + GH + + """ + Gibraltar. + """ + GI + + """ + Greece. + """ + GR + + """ + Greenland. + """ + GL + + """ + Grenada. + """ + GD + + """ + Guadeloupe. + """ + GP + + """ + Guatemala. + """ + GT + + """ + Guernsey. + """ + GG + + """ + Guinea. + """ + GN + + """ + Guinea-Bissau. + """ + GW + + """ + Guyana. + """ + GY + + """ + Haiti. + """ + HT + + """ + Heard & McDonald Islands. + """ + HM + + """ + Vatican City. + """ + VA + + """ + Honduras. + """ + HN + + """ + Hong Kong SAR. + """ + HK + + """ + Hungary. + """ + HU + + """ + Iceland. + """ + IS + + """ + India. + """ + IN + + """ + Indonesia. + """ + ID + + """ + Iran. + """ + IR + + """ + Iraq. + """ + IQ + + """ + Ireland. + """ + IE + + """ + Isle of Man. + """ + IM + + """ + Israel. + """ + IL + + """ + Italy. + """ + IT + + """ + Jamaica. + """ + JM + + """ + Japan. + """ + JP + + """ + Jersey. + """ + JE + + """ + Jordan. + """ + JO + + """ + Kazakhstan. + """ + KZ + + """ + Kenya. + """ + KE + + """ + Kiribati. + """ + KI + + """ + North Korea. + """ + KP + + """ + Kosovo. + """ + XK + + """ + Kuwait. + """ + KW + + """ + Kyrgyzstan. + """ + KG + + """ + Laos. + """ + LA + + """ + Latvia. + """ + LV + + """ + Lebanon. + """ + LB + + """ + Lesotho. + """ + LS + + """ + Liberia. + """ + LR + + """ + Libya. + """ + LY + + """ + Liechtenstein. + """ + LI + + """ + Lithuania. + """ + LT + + """ + Luxembourg. + """ + LU + + """ + Macao SAR. + """ + MO + + """ + Madagascar. + """ + MG + + """ + Malawi. + """ + MW + + """ + Malaysia. + """ + MY + + """ + Maldives. + """ + MV + + """ + Mali. + """ + ML + + """ + Malta. + """ + MT + + """ + Martinique. + """ + MQ + + """ + Mauritania. + """ + MR + + """ + Mauritius. + """ + MU + + """ + Mayotte. + """ + YT + + """ + Mexico. + """ + MX + + """ + Moldova. + """ + MD + + """ + Monaco. + """ + MC + + """ + Mongolia. + """ + MN + + """ + Montenegro. + """ + ME + + """ + Montserrat. + """ + MS + + """ + Morocco. + """ + MA + + """ + Mozambique. + """ + MZ + + """ + Myanmar (Burma). + """ + MM + + """ + Namibia. + """ + NA + + """ + Nauru. + """ + NR + + """ + Nepal. + """ + NP + + """ + Netherlands. + """ + NL + + """ + Netherlands Antilles. + """ + AN + + """ + New Caledonia. + """ + NC + + """ + New Zealand. + """ + NZ + + """ + Nicaragua. + """ + NI + + """ + Niger. + """ + NE + + """ + Nigeria. + """ + NG + + """ + Niue. + """ + NU + + """ + Norfolk Island. + """ + NF + + """ + North Macedonia. + """ + MK + + """ + Norway. + """ + NO + + """ + Oman. + """ + OM + + """ + Pakistan. + """ + PK + + """ + Palestinian Territories. + """ + PS + + """ + Panama. + """ + PA + + """ + Papua New Guinea. + """ + PG + + """ + Paraguay. + """ + PY + + """ + Peru. + """ + PE + + """ + Philippines. + """ + PH + + """ + Pitcairn Islands. + """ + PN + + """ + Poland. + """ + PL + + """ + Portugal. + """ + PT + + """ + Qatar. + """ + QA + + """ + Cameroon. + """ + CM + + """ + Réunion. + """ + RE + + """ + Romania. + """ + RO + + """ + Russia. + """ + RU + + """ + Rwanda. + """ + RW + + """ + St. Barthélemy. + """ + BL + + """ + St. Helena. + """ + SH + + """ + St. Kitts & Nevis. + """ + KN + + """ + St. Lucia. + """ + LC + + """ + St. Martin. + """ + MF + + """ + St. Pierre & Miquelon. + """ + PM + + """ + Samoa. + """ + WS + + """ + San Marino. + """ + SM + + """ + São Tomé & Príncipe. + """ + ST + + """ + Saudi Arabia. + """ + SA + + """ + Senegal. + """ + SN + + """ + Serbia. + """ + RS + + """ + Seychelles. + """ + SC + + """ + Sierra Leone. + """ + SL + + """ + Singapore. + """ + SG + + """ + Sint Maarten. + """ + SX + + """ + Slovakia. + """ + SK + + """ + Slovenia. + """ + SI + + """ + Solomon Islands. + """ + SB + + """ + Somalia. + """ + SO + + """ + South Africa. + """ + ZA + + """ + South Georgia & South Sandwich Islands. + """ + GS + + """ + South Korea. + """ + KR + + """ + South Sudan. + """ + SS + + """ + Spain. + """ + ES + + """ + Sri Lanka. + """ + LK + + """ + St. Vincent & Grenadines. + """ + VC + + """ + Sudan. + """ + SD + + """ + Suriname. + """ + SR + + """ + Svalbard & Jan Mayen. + """ + SJ + + """ + Sweden. + """ + SE + + """ + Switzerland. + """ + CH + + """ + Syria. + """ + SY + + """ + Taiwan. + """ + TW + + """ + Tajikistan. + """ + TJ + + """ + Tanzania. + """ + TZ + + """ + Thailand. + """ + TH + + """ + Timor-Leste. + """ + TL + + """ + Togo. + """ + TG + + """ + Tokelau. + """ + TK + + """ + Tonga. + """ + TO + + """ + Trinidad & Tobago. + """ + TT + + """ + Tunisia. + """ + TN + + """ + Turkey. + """ + TR + + """ + Turkmenistan. + """ + TM + + """ + Turks & Caicos Islands. + """ + TC + + """ + Tuvalu. + """ + TV + + """ + Uganda. + """ + UG + + """ + Ukraine. + """ + UA + + """ + United Arab Emirates. + """ + AE + + """ + United Kingdom. + """ + GB + + """ + United States. + """ + US + + """ + U.S. Outlying Islands. + """ + UM + + """ + Uruguay. + """ + UY + + """ + Uzbekistan. + """ + UZ + + """ + Vanuatu. + """ + VU + + """ + Venezuela. + """ + VE + + """ + Vietnam. + """ + VN + + """ + British Virgin Islands. + """ + VG + + """ + Wallis & Futuna. + """ + WF + + """ + Western Sahara. + """ + EH + + """ + Yemen. + """ + YE + + """ + Zambia. + """ + ZM + + """ + Zimbabwe. + """ + ZW +} + +""" +Credit card information used for a payment. +""" +type CreditCard { + """ + The brand of the credit card. + """ + brand: String + + """ + The expiry month of the credit card. + """ + expiryMonth: Int + + """ + The expiry year of the credit card. + """ + expiryYear: Int + + """ + The credit card's BIN number. + """ + firstDigits: String + + """ + The first name of the card holder. + """ + firstName: String + + """ + The last 4 digits of the credit card. + """ + lastDigits: String + + """ + The last name of the card holder. + """ + lastName: String + + """ + The masked credit card number with only the last 4 digits displayed. + """ + maskedNumber: String +} + +""" +Specifies the fields required to complete a checkout with +a Shopify vaulted credit card payment. +""" +input CreditCardPaymentInput { + """ + The amount of the payment. + """ + amount: Money! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + The ID returned by Shopify's Card Vault. + """ + vaultId: String! + + """ + Executes the payment in test mode if possible. Defaults to `false`. + """ + test: Boolean +} + +""" +Specifies the fields required to complete a checkout with +a Shopify vaulted credit card payment. +""" +input CreditCardPaymentInputV2 { + """ + The amount and currency of the payment. + """ + paymentAmount: MoneyInput! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + The ID returned by Shopify's Card Vault. + """ + vaultId: String! + + """ + Executes the payment in test mode if possible. Defaults to `false`. + """ + test: Boolean +} + +""" +The part of the image that should remain after cropping. +""" +enum CropRegion { + """ + Keep the center of the image. + """ + CENTER + + """ + Keep the top of the image. + """ + TOP + + """ + Keep the bottom of the image. + """ + BOTTOM + + """ + Keep the left of the image. + """ + LEFT + + """ + Keep the right of the image. + """ + RIGHT +} + +""" +Currency codes. +""" +enum CurrencyCode { + """ + United States Dollars (USD). + """ + USD + + """ + Euro (EUR). + """ + EUR + + """ + United Kingdom Pounds (GBP). + """ + GBP + + """ + Canadian Dollars (CAD). + """ + CAD + + """ + Afghan Afghani (AFN). + """ + AFN + + """ + Albanian Lek (ALL). + """ + ALL + + """ + Algerian Dinar (DZD). + """ + DZD + + """ + Angolan Kwanza (AOA). + """ + AOA + + """ + Argentine Pesos (ARS). + """ + ARS + + """ + Armenian Dram (AMD). + """ + AMD + + """ + Aruban Florin (AWG). + """ + AWG + + """ + Australian Dollars (AUD). + """ + AUD + + """ + Barbadian Dollar (BBD). + """ + BBD + + """ + Azerbaijani Manat (AZN). + """ + AZN + + """ + Bangladesh Taka (BDT). + """ + BDT + + """ + Bahamian Dollar (BSD). + """ + BSD + + """ + Bahraini Dinar (BHD). + """ + BHD + + """ + Burundian Franc (BIF). + """ + BIF + + """ + Belarusian Ruble (BYN). + """ + BYN + + """ + Belarusian Ruble (BYR). + """ + BYR + + """ + Belize Dollar (BZD). + """ + BZD + + """ + Bermudian Dollar (BMD). + """ + BMD + + """ + Bhutanese Ngultrum (BTN). + """ + BTN + + """ + Bosnia and Herzegovina Convertible Mark (BAM). + """ + BAM + + """ + Brazilian Real (BRL). + """ + BRL + + """ + Bolivian Boliviano (BOB). + """ + BOB + + """ + Botswana Pula (BWP). + """ + BWP + + """ + Brunei Dollar (BND). + """ + BND + + """ + Bulgarian Lev (BGN). + """ + BGN + + """ + Burmese Kyat (MMK). + """ + MMK + + """ + Cambodian Riel. + """ + KHR + + """ + Cape Verdean escudo (CVE). + """ + CVE + + """ + Cayman Dollars (KYD). + """ + KYD + + """ + Central African CFA Franc (XAF). + """ + XAF + + """ + Chilean Peso (CLP). + """ + CLP + + """ + Chinese Yuan Renminbi (CNY). + """ + CNY + + """ + Colombian Peso (COP). + """ + COP + + """ + Comorian Franc (KMF). + """ + KMF + + """ + Congolese franc (CDF). + """ + CDF + + """ + Costa Rican Colones (CRC). + """ + CRC + + """ + Croatian Kuna (HRK). + """ + HRK + + """ + Czech Koruny (CZK). + """ + CZK + + """ + Danish Kroner (DKK). + """ + DKK + + """ + Djiboutian Franc (DJF). + """ + DJF + + """ + Dominican Peso (DOP). + """ + DOP + + """ + East Caribbean Dollar (XCD). + """ + XCD + + """ + Egyptian Pound (EGP). + """ + EGP + + """ + Eritrean Nakfa (ERN). + """ + ERN + + """ + Ethiopian Birr (ETB). + """ + ETB + + """ + Falkland Islands Pounds (FKP). + """ + FKP + + """ + CFP Franc (XPF). + """ + XPF + + """ + Fijian Dollars (FJD). + """ + FJD + + """ + Gibraltar Pounds (GIP). + """ + GIP + + """ + Gambian Dalasi (GMD). + """ + GMD + + """ + Ghanaian Cedi (GHS). + """ + GHS + + """ + Guatemalan Quetzal (GTQ). + """ + GTQ + + """ + Guyanese Dollar (GYD). + """ + GYD + + """ + Georgian Lari (GEL). + """ + GEL + + """ + Guinean Franc (GNF). + """ + GNF + + """ + Haitian Gourde (HTG). + """ + HTG + + """ + Honduran Lempira (HNL). + """ + HNL + + """ + Hong Kong Dollars (HKD). + """ + HKD + + """ + Hungarian Forint (HUF). + """ + HUF + + """ + Icelandic Kronur (ISK). + """ + ISK + + """ + Indian Rupees (INR). + """ + INR + + """ + Indonesian Rupiah (IDR). + """ + IDR + + """ + Israeli New Shekel (NIS). + """ + ILS + + """ + Iranian Rial (IRR). + """ + IRR + + """ + Iraqi Dinar (IQD). + """ + IQD + + """ + Jamaican Dollars (JMD). + """ + JMD + + """ + Japanese Yen (JPY). + """ + JPY + + """ + Jersey Pound. + """ + JEP + + """ + Jordanian Dinar (JOD). + """ + JOD + + """ + Kazakhstani Tenge (KZT). + """ + KZT + + """ + Kenyan Shilling (KES). + """ + KES + + """ + Kiribati Dollar (KID). + """ + KID + + """ + Kuwaiti Dinar (KWD). + """ + KWD + + """ + Kyrgyzstani Som (KGS). + """ + KGS + + """ + Laotian Kip (LAK). + """ + LAK + + """ + Latvian Lati (LVL). + """ + LVL + + """ + Lebanese Pounds (LBP). + """ + LBP + + """ + Lesotho Loti (LSL). + """ + LSL + + """ + Liberian Dollar (LRD). + """ + LRD + + """ + Libyan Dinar (LYD). + """ + LYD + + """ + Lithuanian Litai (LTL). + """ + LTL + + """ + Malagasy Ariary (MGA). + """ + MGA + + """ + Macedonia Denar (MKD). + """ + MKD + + """ + Macanese Pataca (MOP). + """ + MOP + + """ + Malawian Kwacha (MWK). + """ + MWK + + """ + Maldivian Rufiyaa (MVR). + """ + MVR + + """ + Mauritanian Ouguiya (MRU). + """ + MRU + + """ + Mexican Pesos (MXN). + """ + MXN + + """ + Malaysian Ringgits (MYR). + """ + MYR + + """ + Mauritian Rupee (MUR). + """ + MUR + + """ + Moldovan Leu (MDL). + """ + MDL + + """ + Moroccan Dirham. + """ + MAD + + """ + Mongolian Tugrik. + """ + MNT + + """ + Mozambican Metical. + """ + MZN + + """ + Namibian Dollar. + """ + NAD + + """ + Nepalese Rupee (NPR). + """ + NPR + + """ + Netherlands Antillean Guilder. + """ + ANG + + """ + New Zealand Dollars (NZD). + """ + NZD + + """ + Nicaraguan Córdoba (NIO). + """ + NIO + + """ + Nigerian Naira (NGN). + """ + NGN + + """ + Norwegian Kroner (NOK). + """ + NOK + + """ + Omani Rial (OMR). + """ + OMR + + """ + Panamian Balboa (PAB). + """ + PAB + + """ + Pakistani Rupee (PKR). + """ + PKR + + """ + Papua New Guinean Kina (PGK). + """ + PGK + + """ + Paraguayan Guarani (PYG). + """ + PYG + + """ + Peruvian Nuevo Sol (PEN). + """ + PEN + + """ + Philippine Peso (PHP). + """ + PHP + + """ + Polish Zlotych (PLN). + """ + PLN + + """ + Qatari Rial (QAR). + """ + QAR + + """ + Romanian Lei (RON). + """ + RON + + """ + Russian Rubles (RUB). + """ + RUB + + """ + Rwandan Franc (RWF). + """ + RWF + + """ + Samoan Tala (WST). + """ + WST + + """ + Saint Helena Pounds (SHP). + """ + SHP + + """ + Saudi Riyal (SAR). + """ + SAR + + """ + Sao Tome And Principe Dobra (STD). + """ + STD + + """ + Serbian dinar (RSD). + """ + RSD + + """ + Seychellois Rupee (SCR). + """ + SCR + + """ + Sierra Leonean Leone (SLL). + """ + SLL + + """ + Singapore Dollars (SGD). + """ + SGD + + """ + Sudanese Pound (SDG). + """ + SDG + + """ + Somali Shilling (SOS). + """ + SOS + + """ + Syrian Pound (SYP). + """ + SYP + + """ + South African Rand (ZAR). + """ + ZAR + + """ + South Korean Won (KRW). + """ + KRW + + """ + South Sudanese Pound (SSP). + """ + SSP + + """ + Solomon Islands Dollar (SBD). + """ + SBD + + """ + Sri Lankan Rupees (LKR). + """ + LKR + + """ + Surinamese Dollar (SRD). + """ + SRD + + """ + Swazi Lilangeni (SZL). + """ + SZL + + """ + Swedish Kronor (SEK). + """ + SEK + + """ + Swiss Francs (CHF). + """ + CHF + + """ + Taiwan Dollars (TWD). + """ + TWD + + """ + Thai baht (THB). + """ + THB + + """ + Tajikistani Somoni (TJS). + """ + TJS + + """ + Tanzanian Shilling (TZS). + """ + TZS + + """ + Tongan Pa'anga (TOP). + """ + TOP + + """ + Trinidad and Tobago Dollars (TTD). + """ + TTD + + """ + Tunisian Dinar (TND). + """ + TND + + """ + Turkish Lira (TRY). + """ + TRY + + """ + Turkmenistani Manat (TMT). + """ + TMT + + """ + Ugandan Shilling (UGX). + """ + UGX + + """ + Ukrainian Hryvnia (UAH). + """ + UAH + + """ + United Arab Emirates Dirham (AED). + """ + AED + + """ + Uruguayan Pesos (UYU). + """ + UYU + + """ + Uzbekistan som (UZS). + """ + UZS + + """ + Vanuatu Vatu (VUV). + """ + VUV + + """ + Venezuelan Bolivares (VEF). + """ + VEF + + """ + Venezuelan Bolivares (VES). + """ + VES + + """ + Vietnamese đồng (VND). + """ + VND + + """ + West African CFA franc (XOF). + """ + XOF + + """ + Yemeni Rial (YER). + """ + YER + + """ + Zambian Kwacha (ZMW). + """ + ZMW +} + +""" +A customer represents a customer account with the shop. Customer accounts store contact information for the customer, saving logged-in customers the trouble of having to provide it at every checkout. +""" +type Customer { + """ + Indicates whether the customer has consented to be sent marketing material via email. + """ + acceptsMarketing: Boolean! + + """ + A list of addresses for the customer. + """ + addresses( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MailingAddressConnection! + + """ + The date and time when the customer was created. + """ + createdAt: DateTime! + + """ + The customer’s default address. + """ + defaultAddress: MailingAddress + + """ + The customer’s name, email or phone number. + """ + displayName: String! + + """ + The customer’s email address. + """ + email: String + + """ + The customer’s first name. + """ + firstName: String + + """ + A unique identifier for the customer. + """ + id: ID! + + """ + The customer's most recently updated, incomplete checkout. + """ + lastIncompleteCheckout: Checkout + + """ + The customer’s last name. + """ + lastName: String + + """ + The orders associated with the customer. + """ + orders( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: OrderSortKeys = ID + + """ + Supported filter parameters: + - `processed_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): OrderConnection! + + """ + The customer’s phone number. + """ + phone: String + + """ + A comma separated list of tags that have been added to the customer. + Additional access scope required: unauthenticated_read_customer_tags. + """ + tags: [String!]! + + """ + The date and time when the customer information was updated. + """ + updatedAt: DateTime! +} + +""" +A CustomerAccessToken represents the unique token required to make modifications to the customer object. +""" +type CustomerAccessToken { + """ + The customer’s access token. + """ + accessToken: String! + + """ + The date and time when the customer access token expires. + """ + expiresAt: DateTime! +} + +""" +Specifies the input fields required to create a customer access token. +""" +input CustomerAccessTokenCreateInput { + """ + The email associated to the customer. + """ + email: String! + + """ + The login password to be used by the customer. + """ + password: String! +} + +""" +Return type for `customerAccessTokenCreate` mutation. +""" +type CustomerAccessTokenCreatePayload { + """ + The newly created customer access token object. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerAccessTokenCreateWithMultipass` mutation. +""" +type CustomerAccessTokenCreateWithMultipassPayload { + """ + An access token object associated with the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! +} + +""" +Return type for `customerAccessTokenDelete` mutation. +""" +type CustomerAccessTokenDeletePayload { + """ + The destroyed access token. + """ + deletedAccessToken: String + + """ + ID of the destroyed customer access token. + """ + deletedCustomerAccessTokenId: String + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! +} + +""" +Return type for `customerAccessTokenRenew` mutation. +""" +type CustomerAccessTokenRenewPayload { + """ + The renewed customer access token object. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! +} + +""" +Return type for `customerActivateByUrl` mutation. +""" +type CustomerActivateByUrlPayload { + """ + The customer that was activated. + """ + customer: Customer + + """ + A new customer access token for the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! +} + +""" +Specifies the input fields required to activate a customer. +""" +input CustomerActivateInput { + """ + The activation token required to activate the customer. + """ + activationToken: String! + + """ + New password that will be set during activation. + """ + password: String! +} + +""" +Return type for `customerActivate` mutation. +""" +type CustomerActivatePayload { + """ + The customer object. + """ + customer: Customer + + """ + A newly created customer access token object for the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerAddressCreate` mutation. +""" +type CustomerAddressCreatePayload { + """ + The new customer address object. + """ + customerAddress: MailingAddress + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerAddressDelete` mutation. +""" +type CustomerAddressDeletePayload { + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + ID of the deleted customer address. + """ + deletedCustomerAddressId: String + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerAddressUpdate` mutation. +""" +type CustomerAddressUpdatePayload { + """ + The customer’s updated mailing address. + """ + customerAddress: MailingAddress + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Specifies the fields required to create a new customer. +""" +input CustomerCreateInput { + """ + The customer’s first name. + """ + firstName: String + + """ + The customer’s last name. + """ + lastName: String + + """ + The customer’s email. + """ + email: String! + + """ + A unique phone number for the customer. + + Formatted using E.164 standard. For example, _+16135551111_. + """ + phone: String + + """ + The login password used by the customer. + """ + password: String! + + """ + Indicates whether the customer has consented to be sent marketing material via email. + """ + acceptsMarketing: Boolean +} + +""" +Return type for `customerCreate` mutation. +""" +type CustomerCreatePayload { + """ + The created customer object. + """ + customer: Customer + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerDefaultAddressUpdate` mutation. +""" +type CustomerDefaultAddressUpdatePayload { + """ + The updated customer object. + """ + customer: Customer + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Possible error codes that could be returned by CustomerUserError. +""" +enum CustomerErrorCode { + """ + Input value is blank. + """ + BLANK + + """ + Input value is invalid. + """ + INVALID + + """ + Input value is already taken. + """ + TAKEN + + """ + Input value is too long. + """ + TOO_LONG + + """ + Input value is too short. + """ + TOO_SHORT + + """ + Unidentified customer. + """ + UNIDENTIFIED_CUSTOMER + + """ + Customer is disabled. + """ + CUSTOMER_DISABLED + + """ + Input password starts or ends with whitespace. + """ + PASSWORD_STARTS_OR_ENDS_WITH_WHITESPACE + + """ + Input contains HTML tags. + """ + CONTAINS_HTML_TAGS + + """ + Input contains URL. + """ + CONTAINS_URL + + """ + Invalid activation token. + """ + TOKEN_INVALID + + """ + Customer already enabled. + """ + ALREADY_ENABLED + + """ + Address does not exist. + """ + NOT_FOUND + + """ + Input email contains an invalid domain name. + """ + BAD_DOMAIN + + """ + Multipass token is not valid. + """ + INVALID_MULTIPASS_REQUEST +} + +""" +Return type for `customerRecover` mutation. +""" +type CustomerRecoverPayload { + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Return type for `customerResetByUrl` mutation. +""" +type CustomerResetByUrlPayload { + """ + The customer object which was reset. + """ + customer: Customer + + """ + A newly created customer access token object for the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Specifies the fields required to reset a customer’s password. +""" +input CustomerResetInput { + """ + The reset token required to reset the customer’s password. + """ + resetToken: String! + + """ + New password that will be set as part of the reset password process. + """ + password: String! +} + +""" +Return type for `customerReset` mutation. +""" +type CustomerResetPayload { + """ + The customer object which was reset. + """ + customer: Customer + + """ + A newly created customer access token object for the customer. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Specifies the fields required to update the Customer information. +""" +input CustomerUpdateInput { + """ + The customer’s first name. + """ + firstName: String + + """ + The customer’s last name. + """ + lastName: String + + """ + The customer’s email. + """ + email: String + + """ + A unique phone number for the customer. + + Formatted using E.164 standard. For example, _+16135551111_. To remove the phone number, specify `null`. + """ + phone: String + + """ + The login password used by the customer. + """ + password: String + + """ + Indicates whether the customer has consented to be sent marketing material via email. + """ + acceptsMarketing: Boolean +} + +""" +Return type for `customerUpdate` mutation. +""" +type CustomerUpdatePayload { + """ + The updated customer object. + """ + customer: Customer + + """ + The newly created customer access token. If the customer's password is updated, all previous access tokens + (including the one used to perform this mutation) become invalid, and a new token is generated. + """ + customerAccessToken: CustomerAccessToken + + """ + List of errors that occurred executing the mutation. + """ + customerUserErrors: [CustomerUserError!]! + + """ + List of errors that occurred executing the mutation. + """ + userErrors: [UserError!]! + @deprecated(reason: "Use `customerUserErrors` instead") +} + +""" +Represents an error that happens during execution of a customer mutation. +""" +type CustomerUserError implements DisplayableError { + """ + Error code to uniquely identify the error. + """ + code: CustomerErrorCode + + """ + Path to the input field which caused the error. + """ + field: [String!] + + """ + The error message. + """ + message: String! +} + +""" +An ISO-8601 encoded UTC date time string. Example value: `"2019-07-03T20:47:55Z"`. +""" +scalar DateTime + +""" +A signed decimal number, which supports arbitrary precision and is serialized as a string. Example value: `"29.99"`. +""" +scalar Decimal + +""" +Digital wallet, such as Apple Pay, which can be used for accelerated checkouts. +""" +enum DigitalWallet { + """ + Apple Pay. + """ + APPLE_PAY + + """ + Android Pay. + """ + ANDROID_PAY + + """ + Google Pay. + """ + GOOGLE_PAY + + """ + Shopify Pay. + """ + SHOPIFY_PAY +} + +""" +An amount discounting the line that has been allocated by a discount. +""" +type DiscountAllocation { + """ + Amount of discount allocated. + """ + allocatedAmount: MoneyV2! + + """ + The discount this allocated amount originated from. + """ + discountApplication: DiscountApplication! +} + +""" +Discount applications capture the intentions of a discount source at +the time of application. +""" +interface DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +The method by which the discount's value is allocated onto its entitled lines. +""" +enum DiscountApplicationAllocationMethod { + """ + The value is spread across all entitled lines. + """ + ACROSS + + """ + The value is applied onto every entitled line. + """ + EACH + + """ + The value is specifically applied onto a particular line. + """ + ONE +} + +""" +An auto-generated type for paginating through multiple DiscountApplications. +""" +type DiscountApplicationConnection { + """ + A list of edges. + """ + edges: [DiscountApplicationEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one DiscountApplication and a cursor during pagination. +""" +type DiscountApplicationEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of DiscountApplicationEdge. + """ + node: DiscountApplication! +} + +""" +Which lines on the order that the discount is allocated over, of the type +defined by the Discount Application's target_type. +""" +enum DiscountApplicationTargetSelection { + """ + The discount is allocated onto all the lines. + """ + ALL + + """ + The discount is allocated onto only the lines it is entitled for. + """ + ENTITLED + + """ + The discount is allocated onto explicitly chosen lines. + """ + EXPLICIT +} + +""" +The type of line (i.e. line item or shipping line) on an order that the discount is applicable towards. +""" +enum DiscountApplicationTargetType { + """ + The discount applies onto line items. + """ + LINE_ITEM + + """ + The discount applies onto shipping lines. + """ + SHIPPING_LINE +} + +""" +Discount code applications capture the intentions of a discount code at +the time that it is applied. +""" +type DiscountCodeApplication implements DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + Specifies whether the discount code was applied successfully. + """ + applicable: Boolean! + + """ + The string identifying the discount code that was used at the time of application. + """ + code: String! + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +Represents an error in the input of a mutation. +""" +interface DisplayableError { + """ + Path to the input field which caused the error. + """ + field: [String!] + + """ + The error message. + """ + message: String! +} + +""" +Represents a web address. +""" +type Domain { + """ + The host name of the domain (eg: `example.com`). + """ + host: String! + + """ + Whether SSL is enabled or not. + """ + sslEnabled: Boolean! + + """ + The URL of the domain (eg: `https://example.com`). + """ + url: URL! +} + +""" +Represents a video hosted outside of Shopify. +""" +type ExternalVideo implements Node & Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + The URL. + """ + embeddedUrl: URL! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image +} + +""" +Represents a single fulfillment in an order. +""" +type Fulfillment { + """ + List of the fulfillment's line items. + """ + fulfillmentLineItems( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): FulfillmentLineItemConnection! + + """ + The name of the tracking company. + """ + trackingCompany: String + + """ + Tracking information associated with the fulfillment, + such as the tracking number and tracking URL. + """ + trackingInfo( + """ + Truncate the array result to this size. + """ + first: Int + ): [FulfillmentTrackingInfo!]! +} + +""" +Represents a single line item in a fulfillment. There is at most one fulfillment line item for each order line item. +""" +type FulfillmentLineItem { + """ + The associated order's line item. + """ + lineItem: OrderLineItem! + + """ + The amount fulfilled in this fulfillment. + """ + quantity: Int! +} + +""" +An auto-generated type for paginating through multiple FulfillmentLineItems. +""" +type FulfillmentLineItemConnection { + """ + A list of edges. + """ + edges: [FulfillmentLineItemEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one FulfillmentLineItem and a cursor during pagination. +""" +type FulfillmentLineItemEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of FulfillmentLineItemEdge. + """ + node: FulfillmentLineItem! +} + +""" +Tracking information associated with the fulfillment. +""" +type FulfillmentTrackingInfo { + """ + The tracking number of the fulfillment. + """ + number: String + + """ + The URL to track the fulfillment. + """ + url: URL +} + +""" +A string containing HTML code. Example value: `"<p>Grey cotton knit sweater.</p>"`. +""" +scalar HTML + +""" +Represents information about the metafields associated to the specified resource. +""" +interface HasMetafields { + """ + The metafield associated with the resource. + """ + metafield( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String! + + """ + Identifier for the metafield (maximum of 30 characters). + """ + key: String! + ): Metafield + + """ + A paginated list of metafields associated with the resource. + """ + metafields( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MetafieldConnection! +} + +""" +Represents an image resource. +""" +type Image { + """ + A word or phrase to share the nature or contents of an image. + """ + altText: String + + """ + The original height of the image in pixels. Returns `null` if the image is not hosted by Shopify. + """ + height: Int + + """ + A unique identifier for the image. + """ + id: ID + + """ + The location of the original image as a URL. + + If there are any existing transformations in the original source URL, they will remain and not be stripped. + """ + originalSrc: URL! + + """ + The location of the image as a URL. + """ + src: URL! + @deprecated( + reason: "Previously an image had a single `src` field. This could either return the original image\nlocation or a URL that contained transformations such as sizing or scale.\n\nThese transformations were specified by arguments on the parent field.\n\nNow an image has two distinct URL fields: `originalSrc` and `transformedSrc`.\n\n* `originalSrc` - the original unmodified image URL\n* `transformedSrc` - the image URL with the specified transformations included\n\nTo migrate to the new fields, image transformations should be moved from the parent field to `transformedSrc`.\n\nBefore:\n```graphql\n{\n shop {\n productImages(maxWidth: 200, scale: 2) {\n edges {\n node {\n src\n }\n }\n }\n }\n}\n```\n\nAfter:\n```graphql\n{\n shop {\n productImages {\n edges {\n node {\n transformedSrc(maxWidth: 200, scale: 2)\n }\n }\n }\n }\n}\n```\n" + ) + + """ + The location of the transformed image as a URL. + + All transformation arguments are considered "best-effort". If they can be applied to an image, they will be. + Otherwise any transformations which an image type does not support will be ignored. + """ + transformedSrc( + """ + Image width in pixels between 1 and 5760. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 5760. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. + """ + scale: Int = 1 + + """ + Best effort conversion of image into content type (SVG -> PNG, Anything -> JGP, Anything -> WEBP are supported). + """ + preferredContentType: ImageContentType + ): URL! + + """ + The original width of the image in pixels. Returns `null` if the image is not hosted by Shopify. + """ + width: Int +} + +""" +An auto-generated type for paginating through multiple Images. +""" +type ImageConnection { + """ + A list of edges. + """ + edges: [ImageEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +List of supported image content types. +""" +enum ImageContentType { + """ + A PNG image. + """ + PNG + + """ + A JPG image. + """ + JPG + + """ + A WEBP image. + """ + WEBP +} + +""" +An auto-generated type which holds one Image and a cursor during pagination. +""" +type ImageEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ImageEdge. + """ + node: Image! +} + +""" +Represents a mailing address for customers and shipping. +""" +type MailingAddress implements Node { + """ + The first line of the address. Typically the street address or PO Box number. + """ + address1: String + + """ + The second line of the address. Typically the number of the apartment, suite, or unit. + """ + address2: String + + """ + The name of the city, district, village, or town. + """ + city: String + + """ + The name of the customer's company or organization. + """ + company: String + + """ + The name of the country. + """ + country: String + + """ + The two-letter code for the country of the address. + + For example, US. + """ + countryCode: String @deprecated(reason: "Use `countryCodeV2` instead") + + """ + The two-letter code for the country of the address. + + For example, US. + """ + countryCodeV2: CountryCode + + """ + The first name of the customer. + """ + firstName: String + + """ + A formatted version of the address, customized by the provided arguments. + """ + formatted( + """ + Whether to include the customer's name in the formatted address. + """ + withName: Boolean = false + + """ + Whether to include the customer's company in the formatted address. + """ + withCompany: Boolean = true + ): [String!]! + + """ + A comma-separated list of the values for city, province, and country. + """ + formattedArea: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The last name of the customer. + """ + lastName: String + + """ + The latitude coordinate of the customer address. + """ + latitude: Float + + """ + The longitude coordinate of the customer address. + """ + longitude: Float + + """ + The full name of the customer, based on firstName and lastName. + """ + name: String + + """ + A unique phone number for the customer. + + Formatted using E.164 standard. For example, _+16135551111_. + """ + phone: String + + """ + The region of the address, such as the province, state, or district. + """ + province: String + + """ + The two-letter code for the region. + + For example, ON. + """ + provinceCode: String + + """ + The zip or postal code of the address. + """ + zip: String +} + +""" +An auto-generated type for paginating through multiple MailingAddresses. +""" +type MailingAddressConnection { + """ + A list of edges. + """ + edges: [MailingAddressEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one MailingAddress and a cursor during pagination. +""" +type MailingAddressEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of MailingAddressEdge. + """ + node: MailingAddress! +} + +""" +Specifies the fields accepted to create or update a mailing address. +""" +input MailingAddressInput { + """ + The first line of the address. Typically the street address or PO Box number. + """ + address1: String + + """ + The second line of the address. Typically the number of the apartment, suite, or unit. + """ + address2: String + + """ + The name of the city, district, village, or town. + """ + city: String + + """ + The name of the customer's company or organization. + """ + company: String + + """ + The name of the country. + """ + country: String + + """ + The first name of the customer. + """ + firstName: String + + """ + The last name of the customer. + """ + lastName: String + + """ + A unique phone number for the customer. + + Formatted using E.164 standard. For example, _+16135551111_. + """ + phone: String + + """ + The region of the address, such as the province, state, or district. + """ + province: String + + """ + The zip or postal code of the address. + """ + zip: String +} + +""" +Manual discount applications capture the intentions of a discount that was manually created. +""" +type ManualDiscountApplication implements DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + The description of the application. + """ + description: String + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The title of the application. + """ + title: String! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +Represents a media interface. +""" +interface Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image +} + +""" +An auto-generated type for paginating through multiple Media. +""" +type MediaConnection { + """ + A list of edges. + """ + edges: [MediaEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +The possible content types for a media object. +""" +enum MediaContentType { + """ + An externally hosted video. + """ + EXTERNAL_VIDEO + + """ + A Shopify hosted image. + """ + IMAGE + + """ + A 3d model. + """ + MODEL_3D + + """ + A Shopify hosted video. + """ + VIDEO +} + +""" +An auto-generated type which holds one Media and a cursor during pagination. +""" +type MediaEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of MediaEdge. + """ + node: Media! +} + +""" +Represents a Shopify hosted image. +""" +type MediaImage implements Node & Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The image for the media. + """ + image: Image + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image +} + +""" +Metafields represent custom metadata attached to a resource. Metafields can be sorted into namespaces and are +comprised of keys, values, and value types. +""" +type Metafield implements Node { + """ + The date and time when the storefront metafield was created. + """ + createdAt: DateTime! + + """ + The description of a metafield. + """ + description: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The key name for a metafield. + """ + key: String! + + """ + The namespace for a metafield. + """ + namespace: String! + + """ + The parent object that the metafield belongs to. + """ + parentResource: MetafieldParentResource! + + """ + The date and time when the storefront metafield was updated. + """ + updatedAt: DateTime! + + """ + The value of a metafield. + """ + value: String! + + """ + Represents the metafield value type. + """ + valueType: MetafieldValueType! +} + +""" +An auto-generated type for paginating through multiple Metafields. +""" +type MetafieldConnection { + """ + A list of edges. + """ + edges: [MetafieldEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Metafield and a cursor during pagination. +""" +type MetafieldEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of MetafieldEdge. + """ + node: Metafield! +} + +""" +A resource that the metafield belongs to. +""" +union MetafieldParentResource = Product | ProductVariant + +""" +Metafield value types. +""" +enum MetafieldValueType { + """ + A string metafield. + """ + STRING + + """ + An integer metafield. + """ + INTEGER + + """ + A json string metafield. + """ + JSON_STRING +} + +""" +Represents a Shopify hosted 3D model. +""" +type Model3d implements Node & Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image + + """ + The sources for a 3d model. + """ + sources: [Model3dSource!]! +} + +""" +Represents a source for a Shopify hosted 3d model. +""" +type Model3dSource { + """ + The filesize of the 3d model. + """ + filesize: Int! + + """ + The format of the 3d model. + """ + format: String! + + """ + The MIME type of the 3d model. + """ + mimeType: String! + + """ + The URL of the 3d model. + """ + url: String! +} + +""" +A monetary value string. Example value: `"100.57"`. +""" +scalar Money + +""" +Specifies the fields for a monetary value with currency. +""" +input MoneyInput { + """ + Decimal money amount. + """ + amount: Decimal! + + """ + Currency of the money. + """ + currencyCode: CurrencyCode! +} + +""" +A monetary value with currency. + +To format currencies, combine this type's amount and currencyCode fields with your client's locale. + +For example, in JavaScript you could use Intl.NumberFormat: + +```js +new Intl.NumberFormat(locale, { + style: 'currency', + currency: currencyCode +}).format(amount); +``` + +Other formatting libraries include: + +* iOS - [NumberFormatter](https://developer.apple.com/documentation/foundation/numberformatter) +* Android - [NumberFormat](https://developer.android.com/reference/java/text/NumberFormat.html) +* PHP - [NumberFormatter](http://php.net/manual/en/class.numberformatter.php) + +For a more general solution, the [Unicode CLDR number formatting database] is available with many implementations +(such as [TwitterCldr](https://github.com/twitter/twitter-cldr-rb)). +""" +type MoneyV2 { + """ + Decimal money amount. + """ + amount: Decimal! + + """ + Currency of the money. + """ + currencyCode: CurrencyCode! +} + +""" +An auto-generated type for paginating through multiple MoneyV2s. +""" +type MoneyV2Connection { + """ + A list of edges. + """ + edges: [MoneyV2Edge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one MoneyV2 and a cursor during pagination. +""" +type MoneyV2Edge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of MoneyV2Edge. + """ + node: MoneyV2! +} + +""" +The schema’s entry-point for mutations. This acts as the public, top-level API from which all mutation queries must start. +""" +type Mutation { + """ + Updates the attributes of a checkout. + """ + checkoutAttributesUpdate( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The fields used to update a checkout's attributes. + """ + input: CheckoutAttributesUpdateInput! + ): CheckoutAttributesUpdatePayload + @deprecated(reason: "Use `checkoutAttributesUpdateV2` instead") + + """ + Updates the attributes of a checkout. + """ + checkoutAttributesUpdateV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The checkout attributes to update. + """ + input: CheckoutAttributesUpdateV2Input! + ): CheckoutAttributesUpdateV2Payload + + """ + Completes a checkout without providing payment information. You can use this mutation for free items or items whose purchase price is covered by a gift card. + """ + checkoutCompleteFree( + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutCompleteFreePayload + + """ + Completes a checkout using a credit card token from Shopify's Vault. + """ + checkoutCompleteWithCreditCard( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The credit card info to apply as a payment. + """ + payment: CreditCardPaymentInput! + ): CheckoutCompleteWithCreditCardPayload + @deprecated(reason: "Use `checkoutCompleteWithCreditCardV2` instead") + + """ + Completes a checkout using a credit card token from Shopify's card vault. Before you can complete checkouts using CheckoutCompleteWithCreditCardV2, you need to [_request payment processing_](https://help.shopify.com/api/guides/sales-channel-sdk/getting-started#request-payment-processing). + """ + checkoutCompleteWithCreditCardV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The credit card info to apply as a payment. + """ + payment: CreditCardPaymentInputV2! + ): CheckoutCompleteWithCreditCardV2Payload + + """ + Completes a checkout with a tokenized payment. + """ + checkoutCompleteWithTokenizedPayment( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The info to apply as a tokenized payment. + """ + payment: TokenizedPaymentInput! + ): CheckoutCompleteWithTokenizedPaymentPayload + @deprecated(reason: "Use `checkoutCompleteWithTokenizedPaymentV2` instead") + + """ + Completes a checkout with a tokenized payment. + """ + checkoutCompleteWithTokenizedPaymentV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The info to apply as a tokenized payment. + """ + payment: TokenizedPaymentInputV2! + ): CheckoutCompleteWithTokenizedPaymentV2Payload + @deprecated(reason: "Use `checkoutCompleteWithTokenizedPaymentV3` instead") + + """ + Completes a checkout with a tokenized payment. + """ + checkoutCompleteWithTokenizedPaymentV3( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The info to apply as a tokenized payment. + """ + payment: TokenizedPaymentInputV3! + ): CheckoutCompleteWithTokenizedPaymentV3Payload + + """ + Creates a new checkout. + """ + checkoutCreate( + """ + The fields used to create a checkout. + """ + input: CheckoutCreateInput! + ): CheckoutCreatePayload + + """ + Associates a customer to the checkout. + """ + checkoutCustomerAssociate( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The customer access token of the customer to associate. + """ + customerAccessToken: String! + ): CheckoutCustomerAssociatePayload + @deprecated(reason: "Use `checkoutCustomerAssociateV2` instead") + + """ + Associates a customer to the checkout. + """ + checkoutCustomerAssociateV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The customer access token of the customer to associate. + """ + customerAccessToken: String! + ): CheckoutCustomerAssociateV2Payload + + """ + Disassociates the current checkout customer from the checkout. + """ + checkoutCustomerDisassociate( + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutCustomerDisassociatePayload + @deprecated(reason: "Use `checkoutCustomerDisassociateV2` instead") + + """ + Disassociates the current checkout customer from the checkout. + """ + checkoutCustomerDisassociateV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutCustomerDisassociateV2Payload + + """ + Applies a discount to an existing checkout using a discount code. + """ + checkoutDiscountCodeApply( + """ + The discount code to apply to the checkout. + """ + discountCode: String! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutDiscountCodeApplyPayload + @deprecated(reason: "Use `checkoutDiscountCodeApplyV2` instead") + + """ + Applies a discount to an existing checkout using a discount code. + """ + checkoutDiscountCodeApplyV2( + """ + The discount code to apply to the checkout. + """ + discountCode: String! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutDiscountCodeApplyV2Payload + + """ + Removes the applied discount from an existing checkout. + """ + checkoutDiscountCodeRemove( + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutDiscountCodeRemovePayload + + """ + Updates the email on an existing checkout. + """ + checkoutEmailUpdate( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The email to update the checkout with. + """ + email: String! + ): CheckoutEmailUpdatePayload + @deprecated(reason: "Use `checkoutEmailUpdateV2` instead") + + """ + Updates the email on an existing checkout. + """ + checkoutEmailUpdateV2( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + The email to update the checkout with. + """ + email: String! + ): CheckoutEmailUpdateV2Payload + + """ + Applies a gift card to an existing checkout using a gift card code. This will replace all currently applied gift cards. + """ + checkoutGiftCardApply( + """ + The code of the gift card to apply on the checkout. + """ + giftCardCode: String! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutGiftCardApplyPayload + @deprecated(reason: "Use `checkoutGiftCardsAppend` instead") + + """ + Removes an applied gift card from the checkout. + """ + checkoutGiftCardRemove( + """ + The ID of the Applied Gift Card to remove from the Checkout. + """ + appliedGiftCardId: ID! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutGiftCardRemovePayload + @deprecated(reason: "Use `checkoutGiftCardRemoveV2` instead") + + """ + Removes an applied gift card from the checkout. + """ + checkoutGiftCardRemoveV2( + """ + The ID of the Applied Gift Card to remove from the Checkout. + """ + appliedGiftCardId: ID! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutGiftCardRemoveV2Payload + + """ + Appends gift cards to an existing checkout. + """ + checkoutGiftCardsAppend( + """ + A list of gift card codes to append to the checkout. + """ + giftCardCodes: [String!]! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutGiftCardsAppendPayload + + """ + Adds a list of line items to a checkout. + """ + checkoutLineItemsAdd( + """ + A list of line item objects to add to the checkout. + """ + lineItems: [CheckoutLineItemInput!]! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutLineItemsAddPayload + + """ + Removes line items from an existing checkout. + """ + checkoutLineItemsRemove( + """ + The checkout on which to remove line items. + """ + checkoutId: ID! + + """ + Line item ids to remove. + """ + lineItemIds: [ID!]! + ): CheckoutLineItemsRemovePayload + + """ + Sets a list of line items to a checkout. + """ + checkoutLineItemsReplace( + """ + A list of line item objects to set on the checkout. + """ + lineItems: [CheckoutLineItemInput!]! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutLineItemsReplacePayload + + """ + Updates line items on a checkout. + """ + checkoutLineItemsUpdate( + """ + The checkout on which to update line items. + """ + checkoutId: ID! + + """ + Line items to update. + """ + lineItems: [CheckoutLineItemUpdateInput!]! + ): CheckoutLineItemsUpdatePayload + + """ + Updates the shipping address of an existing checkout. + """ + checkoutShippingAddressUpdate( + """ + The shipping address to where the line items will be shipped. + """ + shippingAddress: MailingAddressInput! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutShippingAddressUpdatePayload + @deprecated(reason: "Use `checkoutShippingAddressUpdateV2` instead") + + """ + Updates the shipping address of an existing checkout. + """ + checkoutShippingAddressUpdateV2( + """ + The shipping address to where the line items will be shipped. + """ + shippingAddress: MailingAddressInput! + + """ + The ID of the checkout. + """ + checkoutId: ID! + ): CheckoutShippingAddressUpdateV2Payload + + """ + Updates the shipping lines on an existing checkout. + """ + checkoutShippingLineUpdate( + """ + The ID of the checkout. + """ + checkoutId: ID! + + """ + A unique identifier to a Checkout’s shipping provider, price, and title combination, enabling the customer to select the availableShippingRates. + """ + shippingRateHandle: String! + ): CheckoutShippingLineUpdatePayload + + """ + Creates a customer access token. + The customer access token is required to modify the customer object in any way. + """ + customerAccessTokenCreate( + """ + The fields used to create a customer access token. + """ + input: CustomerAccessTokenCreateInput! + ): CustomerAccessTokenCreatePayload + + """ + Creates a customer access token using a multipass token instead of email and password. + A customer record is created if customer does not exist. If a customer record already + exists but the record is disabled, then it's enabled. + """ + customerAccessTokenCreateWithMultipass( + """ + A valid multipass token to be authenticated. + """ + multipassToken: String! + ): CustomerAccessTokenCreateWithMultipassPayload + + """ + Permanently destroys a customer access token. + """ + customerAccessTokenDelete( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + ): CustomerAccessTokenDeletePayload + + """ + Renews a customer access token. + + Access token renewal must happen *before* a token expires. + If a token has already expired, a new one should be created instead via `customerAccessTokenCreate`. + """ + customerAccessTokenRenew( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + ): CustomerAccessTokenRenewPayload + + """ + Activates a customer. + """ + customerActivate( + """ + Specifies the customer to activate. + """ + id: ID! + + """ + The fields used to activate a customer. + """ + input: CustomerActivateInput! + ): CustomerActivatePayload + + """ + Activates a customer with the activation url received from `customerCreate`. + """ + customerActivateByUrl( + """ + The customer activation URL. + """ + activationUrl: URL! + + """ + A new password set during activation. + """ + password: String! + ): CustomerActivateByUrlPayload + + """ + Creates a new address for a customer. + """ + customerAddressCreate( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + + """ + The customer mailing address to create. + """ + address: MailingAddressInput! + ): CustomerAddressCreatePayload + + """ + Permanently deletes the address of an existing customer. + """ + customerAddressDelete( + """ + Specifies the address to delete. + """ + id: ID! + + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + ): CustomerAddressDeletePayload + + """ + Updates the address of an existing customer. + """ + customerAddressUpdate( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + + """ + Specifies the customer address to update. + """ + id: ID! + + """ + The customer’s mailing address. + """ + address: MailingAddressInput! + ): CustomerAddressUpdatePayload + + """ + Creates a new customer. + """ + customerCreate( + """ + The fields used to create a new customer. + """ + input: CustomerCreateInput! + ): CustomerCreatePayload + + """ + Updates the default address of an existing customer. + """ + customerDefaultAddressUpdate( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + + """ + ID of the address to set as the new default for the customer. + """ + addressId: ID! + ): CustomerDefaultAddressUpdatePayload + + """ + Sends a reset password email to the customer, as the first step in the reset password process. + """ + customerRecover( + """ + The email address of the customer to recover. + """ + email: String! + ): CustomerRecoverPayload + + """ + Resets a customer’s password with a token received from `CustomerRecover`. + """ + customerReset( + """ + Specifies the customer to reset. + """ + id: ID! + + """ + The fields used to reset a customer’s password. + """ + input: CustomerResetInput! + ): CustomerResetPayload + + """ + Resets a customer’s password with the reset password url received from `CustomerRecover`. + """ + customerResetByUrl( + """ + The customer's reset password url. + """ + resetUrl: URL! + + """ + New password that will be set as part of the reset password process. + """ + password: String! + ): CustomerResetByUrlPayload + + """ + Updates an existing customer. + """ + customerUpdate( + """ + The access token used to identify the customer. + """ + customerAccessToken: String! + + """ + The customer object input. + """ + customer: CustomerUpdateInput! + ): CustomerUpdatePayload +} + +""" +An object with an ID to support global identification. +""" +interface Node { + """ + Globally unique identifier. + """ + id: ID! +} + +""" +An order is a customer’s completed request to purchase one or more products from a shop. An order is created when a customer completes the checkout process, during which time they provides an email address, billing address and payment information. +""" +type Order implements Node { + """ + The reason for the order's cancellation. Returns `null` if the order wasn't canceled. + """ + cancelReason: OrderCancelReason + + """ + The date and time when the order was canceled. Returns null if the order wasn't canceled. + """ + canceledAt: DateTime + + """ + The code of the currency used for the payment. + """ + currencyCode: CurrencyCode! + + """ + The subtotal of line items and their discounts, excluding line items that have been removed. Does not contain order-level discounts, duties, shipping costs, or shipping discounts. Taxes are not included unless the order is a taxes-included order. + """ + currentSubtotalPrice: MoneyV2! + + """ + The total amount of the order, including duties, taxes and discounts, minus amounts for line items that have been removed. + """ + currentTotalPrice: MoneyV2! + + """ + The total of all taxes applied to the order, excluding taxes for returned line items. + """ + currentTotalTax: MoneyV2! + + """ + The locale code in which this specific order happened. + """ + customerLocale: String + + """ + The unique URL that the customer can use to access the order. + """ + customerUrl: URL + + """ + Discounts that have been applied on the order. + """ + discountApplications( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): DiscountApplicationConnection! + + """ + Whether the order has had any edits applied or not. + """ + edited: Boolean! + + """ + The customer's email address. + """ + email: String + + """ + The financial status of the order. + """ + financialStatus: OrderFinancialStatus + + """ + The fulfillment status for the order. + """ + fulfillmentStatus: OrderFulfillmentStatus! + + """ + Globally unique identifier. + """ + id: ID! + + """ + List of the order’s line items. + """ + lineItems( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): OrderLineItemConnection! + + """ + Unique identifier for the order that appears on the order. + For example, _#1000_ or _Store1001. + """ + name: String! + + """ + A unique numeric identifier for the order for use by shop owner and customer. + """ + orderNumber: Int! + + """ + The total price of the order before any applied edits. + """ + originalTotalPrice: MoneyV2! + + """ + The customer's phone number for receiving SMS notifications. + """ + phone: String + + """ + The date and time when the order was imported. + This value can be set to dates in the past when importing from other systems. + If no value is provided, it will be auto-generated based on current date and time. + """ + processedAt: DateTime! + + """ + The address to where the order will be shipped. + """ + shippingAddress: MailingAddress + + """ + The discounts that have been allocated onto the shipping line by discount applications. + """ + shippingDiscountAllocations: [DiscountAllocation!]! + + """ + The unique URL for the order's status page. + """ + statusUrl: URL! + + """ + Price of the order before shipping and taxes. + """ + subtotalPrice: Money @deprecated(reason: "Use `subtotalPriceV2` instead") + + """ + Price of the order before duties, shipping and taxes. + """ + subtotalPriceV2: MoneyV2 + + """ + List of the order’s successful fulfillments. + """ + successfulFulfillments( + """ + Truncate the array result to this size. + """ + first: Int + ): [Fulfillment!] + + """ + The sum of all the prices of all the items in the order, taxes and discounts included (must be positive). + """ + totalPrice: Money! @deprecated(reason: "Use `totalPriceV2` instead") + + """ + The sum of all the prices of all the items in the order, duties, taxes and discounts included (must be positive). + """ + totalPriceV2: MoneyV2! + + """ + The total amount that has been refunded. + """ + totalRefunded: Money! @deprecated(reason: "Use `totalRefundedV2` instead") + + """ + The total amount that has been refunded. + """ + totalRefundedV2: MoneyV2! + + """ + The total cost of shipping. + """ + totalShippingPrice: Money! + @deprecated(reason: "Use `totalShippingPriceV2` instead") + + """ + The total cost of shipping. + """ + totalShippingPriceV2: MoneyV2! + + """ + The total cost of taxes. + """ + totalTax: Money @deprecated(reason: "Use `totalTaxV2` instead") + + """ + The total cost of taxes. + """ + totalTaxV2: MoneyV2 +} + +""" +Represents the reason for the order's cancellation. +""" +enum OrderCancelReason { + """ + The customer wanted to cancel the order. + """ + CUSTOMER + + """ + The order was fraudulent. + """ + FRAUD + + """ + There was insufficient inventory. + """ + INVENTORY + + """ + Payment was declined. + """ + DECLINED + + """ + The order was canceled for an unlisted reason. + """ + OTHER +} + +""" +An auto-generated type for paginating through multiple Orders. +""" +type OrderConnection { + """ + A list of edges. + """ + edges: [OrderEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Order and a cursor during pagination. +""" +type OrderEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of OrderEdge. + """ + node: Order! +} + +""" +Represents the order's current financial status. +""" +enum OrderFinancialStatus { + """ + Displayed as **Pending**. + """ + PENDING + + """ + Displayed as **Authorized**. + """ + AUTHORIZED + + """ + Displayed as **Partially paid**. + """ + PARTIALLY_PAID + + """ + Displayed as **Partially refunded**. + """ + PARTIALLY_REFUNDED + + """ + Displayed as **Voided**. + """ + VOIDED + + """ + Displayed as **Paid**. + """ + PAID + + """ + Displayed as **Refunded**. + """ + REFUNDED +} + +""" +Represents the order's current fulfillment status. +""" +enum OrderFulfillmentStatus { + """ + Displayed as **Unfulfilled**. + """ + UNFULFILLED + + """ + Displayed as **Partially fulfilled**. + """ + PARTIALLY_FULFILLED + + """ + Displayed as **Fulfilled**. + """ + FULFILLED + + """ + Displayed as **Restocked**. + """ + RESTOCKED + + """ + Displayed as **Pending fulfillment**. + """ + PENDING_FULFILLMENT + + """ + Displayed as **Open**. + """ + OPEN + + """ + Displayed as **In progress**. + """ + IN_PROGRESS + + """ + Displayed as **Scheduled**. + """ + SCHEDULED +} + +""" +Represents a single line in an order. There is one line item for each distinct product variant. +""" +type OrderLineItem { + """ + The number of entries associated to the line item minus the items that have been removed. + """ + currentQuantity: Int! + + """ + List of custom attributes associated to the line item. + """ + customAttributes: [Attribute!]! + + """ + The discounts that have been allocated onto the order line item by discount applications. + """ + discountAllocations: [DiscountAllocation!]! + + """ + The total price of the line item, including discounts, and displayed in the presentment currency. + """ + discountedTotalPrice: MoneyV2! + + """ + The total price of the line item, not including any discounts. The total price is calculated using the original unit price multiplied by the quantity, and it is displayed in the presentment currency. + """ + originalTotalPrice: MoneyV2! + + """ + The number of products variants associated to the line item. + """ + quantity: Int! + + """ + The title of the product combined with title of the variant. + """ + title: String! + + """ + The product variant object associated to the line item. + """ + variant: ProductVariant +} + +""" +An auto-generated type for paginating through multiple OrderLineItems. +""" +type OrderLineItemConnection { + """ + A list of edges. + """ + edges: [OrderLineItemEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one OrderLineItem and a cursor during pagination. +""" +type OrderLineItemEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of OrderLineItemEdge. + """ + node: OrderLineItem! +} + +""" +The set of valid sort keys for the Order query. +""" +enum OrderSortKeys { + """ + Sort by the `processed_at` value. + """ + PROCESSED_AT + + """ + Sort by the `total_price` value. + """ + TOTAL_PRICE + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +Shopify merchants can create pages to hold static HTML content. Each Page object represents a custom page on the online store. +""" +type Page implements Node { + """ + The description of the page, complete with HTML formatting. + """ + body: HTML! + + """ + Summary of the page body. + """ + bodySummary: String! + + """ + The timestamp of the page creation. + """ + createdAt: DateTime! + + """ + A human-friendly unique string for the page automatically generated from its title. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + The page's SEO information. + """ + seo: SEO + + """ + The title of the page. + """ + title: String! + + """ + The timestamp of the latest page update. + """ + updatedAt: DateTime! + + """ + The url pointing to the page accessible from the web. + """ + url: URL! +} + +""" +An auto-generated type for paginating through multiple Pages. +""" +type PageConnection { + """ + A list of edges. + """ + edges: [PageEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Page and a cursor during pagination. +""" +type PageEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of PageEdge. + """ + node: Page! +} + +""" +Information about pagination in a connection. +""" +type PageInfo { + """ + Indicates if there are more pages to fetch. + """ + hasNextPage: Boolean! + + """ + Indicates if there are any pages prior to the current page. + """ + hasPreviousPage: Boolean! +} + +""" +The set of valid sort keys for the Page query. +""" +enum PageSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `updated_at` value. + """ + UPDATED_AT + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +A payment applied to a checkout. +""" +type Payment implements Node { + """ + The amount of the payment. + """ + amount: Money! @deprecated(reason: "Use `amountV2` instead") + + """ + The amount of the payment. + """ + amountV2: MoneyV2! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddress + + """ + The checkout to which the payment belongs. + """ + checkout: Checkout! + + """ + The credit card used for the payment in the case of direct payments. + """ + creditCard: CreditCard + + """ + A message describing a processing error during asynchronous processing. + """ + errorMessage: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + A client-side generated token to identify a payment and perform idempotent operations. + """ + idempotencyKey: String + + """ + The URL where the customer needs to be redirected so they can complete the 3D Secure payment flow. + """ + nextActionUrl: URL + + """ + Whether or not the payment is still processing asynchronously. + """ + ready: Boolean! + + """ + A flag to indicate if the payment is to be done in test mode for gateways that support it. + """ + test: Boolean! + + """ + The actual transaction recorded by Shopify after having processed the payment with the gateway. + """ + transaction: Transaction +} + +""" +Settings related to payments. +""" +type PaymentSettings { + """ + List of the card brands which the shop accepts. + """ + acceptedCardBrands: [CardBrand!]! + + """ + The url pointing to the endpoint to vault credit cards. + """ + cardVaultUrl: URL! + + """ + The country where the shop is located. + """ + countryCode: CountryCode! + + """ + The three-letter code for the shop's primary currency. + """ + currencyCode: CurrencyCode! + + """ + A list of enabled currencies (ISO 4217 format) that the shop accepts. Merchants can enable currencies from their Shopify Payments settings in the Shopify admin. + """ + enabledPresentmentCurrencies: [CurrencyCode!]! + + """ + The shop’s Shopify Payments account id. + """ + shopifyPaymentsAccountId: String + + """ + List of the digital wallets which the shop supports. + """ + supportedDigitalWallets: [DigitalWallet!]! +} + +""" +The valid values for the types of payment token. +""" +enum PaymentTokenType { + """ + Apple Pay token type. + """ + APPLE_PAY + + """ + Vault payment token type. + """ + VAULT + + """ + Shopify Pay token type. + """ + SHOPIFY_PAY + + """ + Google Pay token type. + """ + GOOGLE_PAY +} + +""" +The value of the percentage pricing object. +""" +type PricingPercentageValue { + """ + The percentage value of the object. + """ + percentage: Float! +} + +""" +The price value (fixed or percentage) for a discount application. +""" +union PricingValue = MoneyV2 | PricingPercentageValue + +""" +A product represents an individual item for sale in a Shopify store. Products are often physical, but they don't have to be. +For example, a digital download (such as a movie, music or ebook file) also qualifies as a product, as do services (such as equipment rental, work for hire, customization of another product or an extended warranty). +""" +type Product implements Node & HasMetafields { + """ + Indicates if at least one product variant is available for sale. + """ + availableForSale: Boolean! + + """ + List of collections a product belongs to. + """ + collections( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): CollectionConnection! + + """ + The compare at price of the product across all variants. + """ + compareAtPriceRange: ProductPriceRange! + + """ + The date and time when the product was created. + """ + createdAt: DateTime! + + """ + Stripped description of the product, single line with HTML tags removed. + """ + description( + """ + Truncates string after the given length. + """ + truncateAt: Int + ): String! + + """ + The description of the product, complete with HTML formatting. + """ + descriptionHtml: HTML! + + """ + A human-friendly unique string for the Product automatically generated from its title. + They are used by the Liquid templating language to refer to objects. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + List of images associated with the product. + """ + images( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductImageSortKeys = POSITION + + """ + Image width in pixels between 1 and 2048. This argument is deprecated: Use `maxWidth` on `Image.transformedSrc` instead. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 2048. This argument is deprecated: Use `maxHeight` on `Image.transformedSrc` instead. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. This argument is deprecated: Use `crop` on `Image.transformedSrc` instead. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. This argument is deprecated: Use `scale` on `Image.transformedSrc` instead. + """ + scale: Int = 1 + ): ImageConnection! + + """ + The media associated with the product. + """ + media( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductMediaSortKeys = POSITION + ): MediaConnection! + + """ + The metafield associated with the resource. + """ + metafield( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String! + + """ + Identifier for the metafield (maximum of 30 characters). + """ + key: String! + ): Metafield + + """ + A paginated list of metafields associated with the resource. + """ + metafields( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MetafieldConnection! + + """ + The online store URL for the product. + A value of `null` indicates that the product is not published to the Online Store sales channel. + """ + onlineStoreUrl: URL + + """ + List of product options. + """ + options( + """ + Truncate the array result to this size. + """ + first: Int + ): [ProductOption!]! + + """ + List of price ranges in the presentment currencies for this shop. + """ + presentmentPriceRanges( + """ + Specifies the presentment currencies to return a price range in. + """ + presentmentCurrencies: [CurrencyCode!] + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): ProductPriceRangeConnection! + + """ + The price range. + """ + priceRange: ProductPriceRange! + + """ + A categorization that a product can be tagged with, commonly used for filtering and searching. + """ + productType: String! + + """ + The date and time when the product was published to the channel. + """ + publishedAt: DateTime! + + """ + The product's SEO information. + """ + seo: SEO! + + """ + A comma separated list of tags that have been added to the product. + Additional access scope required for private apps: unauthenticated_read_product_tags. + """ + tags: [String!]! + + """ + The product’s title. + """ + title: String! + + """ + The total quantity of inventory in stock for this Product. + """ + totalInventory: Int + + """ + The date and time when the product was last modified. + A product's `updatedAt` value can change for different reasons. For example, if an order + is placed for a product that has inventory tracking set up, then the inventory adjustment + is counted as an update. + """ + updatedAt: DateTime! + + """ + Find a product’s variant based on its selected options. + This is useful for converting a user’s selection of product options into a single matching variant. + If there is not a variant for the selected options, `null` will be returned. + """ + variantBySelectedOptions( + """ + The input fields used for a selected option. + """ + selectedOptions: [SelectedOptionInput!]! + ): ProductVariant + + """ + List of the product’s variants. + """ + variants( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductVariantSortKeys = POSITION + ): ProductVariantConnection! + + """ + The product’s vendor name. + """ + vendor: String! +} + +""" +The set of valid sort keys for the ProductCollection query. +""" +enum ProductCollectionSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `price` value. + """ + PRICE + + """ + Sort by the `best-selling` value. + """ + BEST_SELLING + + """ + Sort by the `created` value. + """ + CREATED + + """ + Sort by the `id` value. + """ + ID + + """ + Sort by the `manual` value. + """ + MANUAL + + """ + Sort by the `collection-default` value. + """ + COLLECTION_DEFAULT + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +An auto-generated type for paginating through multiple Products. +""" +type ProductConnection { + """ + A list of edges. + """ + edges: [ProductEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one Product and a cursor during pagination. +""" +type ProductEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ProductEdge. + """ + node: Product! +} + +""" +The set of valid sort keys for the ProductImage query. +""" +enum ProductImageSortKeys { + """ + Sort by the `created_at` value. + """ + CREATED_AT + + """ + Sort by the `position` value. + """ + POSITION + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +The set of valid sort keys for the ProductMedia query. +""" +enum ProductMediaSortKeys { + """ + Sort by the `position` value. + """ + POSITION + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +Product property names like "Size", "Color", and "Material" that the customers can select. +Variants are selected based on permutations of these options. +255 characters limit each. +""" +type ProductOption implements Node { + """ + Globally unique identifier. + """ + id: ID! + + """ + The product option’s name. + """ + name: String! + + """ + The corresponding value to the product option name. + """ + values: [String!]! +} + +""" +The price range of the product. +""" +type ProductPriceRange { + """ + The highest variant's price. + """ + maxVariantPrice: MoneyV2! + + """ + The lowest variant's price. + """ + minVariantPrice: MoneyV2! +} + +""" +An auto-generated type for paginating through multiple ProductPriceRanges. +""" +type ProductPriceRangeConnection { + """ + A list of edges. + """ + edges: [ProductPriceRangeEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one ProductPriceRange and a cursor during pagination. +""" +type ProductPriceRangeEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ProductPriceRangeEdge. + """ + node: ProductPriceRange! +} + +""" +The set of valid sort keys for the Product query. +""" +enum ProductSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `product_type` value. + """ + PRODUCT_TYPE + + """ + Sort by the `vendor` value. + """ + VENDOR + + """ + Sort by the `updated_at` value. + """ + UPDATED_AT + + """ + Sort by the `created_at` value. + """ + CREATED_AT + + """ + Sort by the `best_selling` value. + """ + BEST_SELLING + + """ + Sort by the `price` value. + """ + PRICE + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +A product variant represents a different version of a product, such as differing sizes or differing colors. +""" +type ProductVariant implements Node & HasMetafields { + """ + Indicates if the product variant is in stock. + """ + available: Boolean @deprecated(reason: "Use `availableForSale` instead") + + """ + Indicates if the product variant is available for sale. + """ + availableForSale: Boolean! + + """ + The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPrice` is higher than `price`. + """ + compareAtPrice: Money @deprecated(reason: "Use `compareAtPriceV2` instead") + + """ + The compare at price of the variant. This can be used to mark a variant as on sale, when `compareAtPriceV2` is higher than `priceV2`. + """ + compareAtPriceV2: MoneyV2 + + """ + Whether a product is out of stock but still available for purchase (used for backorders). + """ + currentlyNotInStock: Boolean! + + """ + Globally unique identifier. + """ + id: ID! + + """ + Image associated with the product variant. This field falls back to the product image if no image is available. + """ + image( + """ + Image width in pixels between 1 and 2048. This argument is deprecated: Use `maxWidth` on `Image.transformedSrc` instead. + """ + maxWidth: Int + + """ + Image height in pixels between 1 and 2048. This argument is deprecated: Use `maxHeight` on `Image.transformedSrc` instead. + """ + maxHeight: Int + + """ + Crops the image according to the specified region. This argument is deprecated: Use `crop` on `Image.transformedSrc` instead. + """ + crop: CropRegion + + """ + Image size multiplier for high-resolution retina displays. Must be between 1 and 3. This argument is deprecated: Use `scale` on `Image.transformedSrc` instead. + """ + scale: Int = 1 + ): Image + + """ + The metafield associated with the resource. + """ + metafield( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String! + + """ + Identifier for the metafield (maximum of 30 characters). + """ + key: String! + ): Metafield + + """ + A paginated list of metafields associated with the resource. + """ + metafields( + """ + Container for a set of metafields (maximum of 20 characters). + """ + namespace: String + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MetafieldConnection! + + """ + List of prices and compare-at prices in the presentment currencies for this shop. + """ + presentmentPrices( + """ + The presentment currencies prices should return in. + """ + presentmentCurrencies: [CurrencyCode!] + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): ProductVariantPricePairConnection! + + """ + List of unit prices in the presentment currencies for this shop. + """ + presentmentUnitPrices( + """ + Specify the currencies in which to return presentment unit prices. + """ + presentmentCurrencies: [CurrencyCode!] + + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + ): MoneyV2Connection! + + """ + The product variant’s price. + """ + price: Money! @deprecated(reason: "Use `priceV2` instead") + + """ + The product variant’s price. + """ + priceV2: MoneyV2! + + """ + The product object that the product variant belongs to. + """ + product: Product! + + """ + The total sellable quantity of the variant for online sales channels. + """ + quantityAvailable: Int + + """ + Whether a customer needs to provide a shipping address when placing an order for the product variant. + """ + requiresShipping: Boolean! + + """ + List of product options applied to the variant. + """ + selectedOptions: [SelectedOption!]! + + """ + The SKU (stock keeping unit) associated with the variant. + """ + sku: String + + """ + The product variant’s title. + """ + title: String! + + """ + The unit price value for the variant based on the variant's measurement. + """ + unitPrice: MoneyV2 + + """ + The unit price measurement for the variant. + """ + unitPriceMeasurement: UnitPriceMeasurement + + """ + The weight of the product variant in the unit system specified with `weight_unit`. + """ + weight: Float + + """ + Unit of measurement for weight. + """ + weightUnit: WeightUnit! +} + +""" +An auto-generated type for paginating through multiple ProductVariants. +""" +type ProductVariantConnection { + """ + A list of edges. + """ + edges: [ProductVariantEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one ProductVariant and a cursor during pagination. +""" +type ProductVariantEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ProductVariantEdge. + """ + node: ProductVariant! +} + +""" +The compare-at price and price of a variant sharing a currency. +""" +type ProductVariantPricePair { + """ + The compare-at price of the variant with associated currency. + """ + compareAtPrice: MoneyV2 + + """ + The price of the variant with associated currency. + """ + price: MoneyV2! +} + +""" +An auto-generated type for paginating through multiple ProductVariantPricePairs. +""" +type ProductVariantPricePairConnection { + """ + A list of edges. + """ + edges: [ProductVariantPricePairEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one ProductVariantPricePair and a cursor during pagination. +""" +type ProductVariantPricePairEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of ProductVariantPricePairEdge. + """ + node: ProductVariantPricePair! +} + +""" +The set of valid sort keys for the ProductVariant query. +""" +enum ProductVariantSortKeys { + """ + Sort by the `title` value. + """ + TITLE + + """ + Sort by the `sku` value. + """ + SKU + + """ + Sort by the `position` value. + """ + POSITION + + """ + Sort by the `id` value. + """ + ID + + """ + During a search (i.e. when the `query` parameter has been specified on the connection) this sorts the + results by relevance to the search term(s). When no search query is specified, this sort key is not + deterministic and should not be used. + """ + RELEVANCE +} + +""" +The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. +""" +type QueryRoot { + """ + List of the shop's articles. + """ + articles( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ArticleSortKeys = ID + + """ + Supported filter parameters: + - `author` + - `blog_title` + - `created_at` + - `tag` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ArticleConnection! + + """ + Find a blog by its handle. + """ + blogByHandle( + """ + The handle of the blog. + """ + handle: String! + ): Blog + + """ + List of the shop's blogs. + """ + blogs( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: BlogSortKeys = ID + + """ + Supported filter parameters: + - `created_at` + - `handle` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): BlogConnection! + + """ + Find a collection by its handle. + """ + collectionByHandle( + """ + The handle of the collection. + """ + handle: String! + ): Collection + + """ + List of the shop’s collections. + """ + collections( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: CollectionSortKeys = ID + + """ + Supported filter parameters: + - `collection_type` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): CollectionConnection! + + """ + Find a customer by its access token. + """ + customer( + """ + The customer access token. + """ + customerAccessToken: String! + ): Customer + node( + """ + The ID of the Node to return. + """ + id: ID! + ): Node + nodes( + """ + The IDs of the Nodes to return. + """ + ids: [ID!]! + ): [Node]! + + """ + Find a page by its handle. + """ + pageByHandle( + """ + The handle of the page. + """ + handle: String! + ): Page + + """ + List of the shop's pages. + """ + pages( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: PageSortKeys = ID + + """ + Supported filter parameters: + - `created_at` + - `handle` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): PageConnection! + + """ + Find a product by its handle. + """ + productByHandle( + """ + The handle of the product. + """ + handle: String! + ): Product + + """ + Find recommended products related to a given `product_id`. + To learn more about how recommendations are generated, see + [*Showing product recommendations on product pages*](https://help.shopify.com/themes/development/recommended-products). + """ + productRecommendations( + """ + The id of the product. + """ + productId: ID! + ): [Product!] + + """ + Tags added to products. + Additional access scope required: unauthenticated_read_product_tags. + """ + productTags( + """ + Returns up to the first `n` elements from the list. + """ + first: Int! + ): StringConnection! + + """ + List of product types for the shop's products that are published to your app. + """ + productTypes( + """ + Returns up to the first `n` elements from the list. + """ + first: Int! + ): StringConnection! + + """ + List of the shop’s products. + """ + products( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductSortKeys = ID + + """ + Supported filter parameters: + - `available_for_sale` + - `created_at` + - `product_type` + - `tag` + - `title` + - `updated_at` + - `variants.price` + - `vendor` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ProductConnection! + + """ + The list of public Storefront API versions, including supported, release candidate and unstable versions. + """ + publicApiVersions: [ApiVersion!]! + + """ + The shop associated with the storefront access token. + """ + shop: Shop! +} + +""" +SEO information. +""" +type SEO { + """ + The meta description. + """ + description: String + + """ + The SEO title. + """ + title: String +} + +""" +Script discount applications capture the intentions of a discount that +was created by a Shopify Script. +""" +type ScriptDiscountApplication implements DiscountApplication { + """ + The method by which the discount's value is allocated to its entitled items. + """ + allocationMethod: DiscountApplicationAllocationMethod! + + """ + The description of the application as defined by the Script. + """ + description: String! @deprecated(reason: "Use `title` instead") + + """ + Which lines of targetType that the discount is allocated over. + """ + targetSelection: DiscountApplicationTargetSelection! + + """ + The type of line that the discount is applicable towards. + """ + targetType: DiscountApplicationTargetType! + + """ + The title of the application as defined by the Script. + """ + title: String! + + """ + The value of the discount application. + """ + value: PricingValue! +} + +""" +Properties used by customers to select a product variant. +Products can have multiple options, like different sizes or colors. +""" +type SelectedOption { + """ + The product option’s name. + """ + name: String! + + """ + The product option’s value. + """ + value: String! +} + +""" +Specifies the input fields required for a selected option. +""" +input SelectedOptionInput { + """ + The product option’s name. + """ + name: String! + + """ + The product option’s value. + """ + value: String! +} + +""" +A shipping rate to be applied to a checkout. +""" +type ShippingRate { + """ + Human-readable unique identifier for this shipping rate. + """ + handle: String! + + """ + Price of this shipping rate. + """ + price: Money! @deprecated(reason: "Use `priceV2` instead") + + """ + Price of this shipping rate. + """ + priceV2: MoneyV2! + + """ + Title of this shipping rate. + """ + title: String! +} + +""" +Shop represents a collection of the general settings and information about the shop. +""" +type Shop { + """ + List of the shop' articles. + """ + articles( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ArticleSortKeys = ID + + """ + Supported filter parameters: + - `author` + - `blog_title` + - `created_at` + - `tag` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ArticleConnection! @deprecated(reason: "Use `QueryRoot.articles` instead.") + + """ + List of the shop' blogs. + """ + blogs( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: BlogSortKeys = ID + + """ + Supported filter parameters: + - `created_at` + - `handle` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): BlogConnection! @deprecated(reason: "Use `QueryRoot.blogs` instead.") + + """ + Find a collection by its handle. + """ + collectionByHandle( + """ + The handle of the collection. + """ + handle: String! + ): Collection + @deprecated(reason: "Use `QueryRoot.collectionByHandle` instead.") + + """ + List of the shop’s collections. + """ + collections( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: CollectionSortKeys = ID + + """ + Supported filter parameters: + - `collection_type` + - `title` + - `updated_at` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): CollectionConnection! + @deprecated(reason: "Use `QueryRoot.collections` instead.") + + """ + The three-letter code for the currency that the shop accepts. + """ + currencyCode: CurrencyCode! + @deprecated(reason: "Use `paymentSettings` instead") + + """ + A description of the shop. + """ + description: String + + """ + A string representing the way currency is formatted when the currency isn’t specified. + """ + moneyFormat: String! + + """ + The shop’s name. + """ + name: String! + + """ + Settings related to payments. + """ + paymentSettings: PaymentSettings! + + """ + The shop’s primary domain. + """ + primaryDomain: Domain! + + """ + The shop’s privacy policy. + """ + privacyPolicy: ShopPolicy + + """ + Find a product by its handle. + """ + productByHandle( + """ + The handle of the product. + """ + handle: String! + ): Product @deprecated(reason: "Use `QueryRoot.productByHandle` instead.") + + """ + A list of tags that have been added to products. + Additional access scope required: unauthenticated_read_product_tags. + """ + productTags( + """ + Returns up to the first `n` elements from the list. + """ + first: Int! + ): StringConnection! + @deprecated(reason: "Use `QueryRoot.productTags` instead.") + + """ + List of the shop’s product types. + """ + productTypes( + """ + Returns up to the first `n` elements from the list. + """ + first: Int! + ): StringConnection! + @deprecated(reason: "Use `QueryRoot.productTypes` instead.") + + """ + List of the shop’s products. + """ + products( + """ + Returns up to the first `n` elements from the list. + """ + first: Int + + """ + Returns the elements that come after the specified cursor. + """ + after: String + + """ + Returns up to the last `n` elements from the list. + """ + last: Int + + """ + Returns the elements that come before the specified cursor. + """ + before: String + + """ + Reverse the order of the underlying list. + """ + reverse: Boolean = false + + """ + Sort the underlying list by the given key. + """ + sortKey: ProductSortKeys = ID + + """ + Supported filter parameters: + - `available_for_sale` + - `created_at` + - `product_type` + - `tag` + - `title` + - `updated_at` + - `variants.price` + - `vendor` + + See the detailed [search syntax](https://help.shopify.com/api/getting-started/search-syntax) + for more information about using filters. + """ + query: String + ): ProductConnection! @deprecated(reason: "Use `QueryRoot.products` instead.") + + """ + The shop’s refund policy. + """ + refundPolicy: ShopPolicy + + """ + The shop’s shipping policy. + """ + shippingPolicy: ShopPolicy + + """ + Countries that the shop ships to. + """ + shipsToCountries: [CountryCode!]! + + """ + The shop’s Shopify Payments account id. + """ + shopifyPaymentsAccountId: String + @deprecated(reason: "Use `paymentSettings` instead") + + """ + The shop’s terms of service. + """ + termsOfService: ShopPolicy +} + +""" +Policy that a merchant has configured for their store, such as their refund or privacy policy. +""" +type ShopPolicy implements Node { + """ + Policy text, maximum size of 64kb. + """ + body: String! + + """ + Policy’s handle. + """ + handle: String! + + """ + Globally unique identifier. + """ + id: ID! + + """ + Policy’s title. + """ + title: String! + + """ + Public URL to the policy. + """ + url: URL! +} + +""" +An auto-generated type for paginating through multiple Strings. +""" +type StringConnection { + """ + A list of edges. + """ + edges: [StringEdge!]! + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An auto-generated type which holds one String and a cursor during pagination. +""" +type StringEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of StringEdge. + """ + node: String! +} + +""" +Specifies the fields required to complete a checkout with +a tokenized payment. +""" +input TokenizedPaymentInput { + """ + The amount of the payment. + """ + amount: Money! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + The type of payment token. + """ + type: String! + + """ + A simple string or JSON containing the required payment data for the tokenized payment. + """ + paymentData: String! + + """ + Executes the payment in test mode if possible. Defaults to `false`. + """ + test: Boolean + + """ + Public Hash Key used for AndroidPay payments only. + """ + identifier: String +} + +""" +Specifies the fields required to complete a checkout with +a tokenized payment. +""" +input TokenizedPaymentInputV2 { + """ + The amount and currency of the payment. + """ + paymentAmount: MoneyInput! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + A simple string or JSON containing the required payment data for the tokenized payment. + """ + paymentData: String! + + """ + Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`. + """ + test: Boolean + + """ + Public Hash Key used for AndroidPay payments only. + """ + identifier: String + + """ + The type of payment token. + """ + type: String! +} + +""" +Specifies the fields required to complete a checkout with +a tokenized payment. +""" +input TokenizedPaymentInputV3 { + """ + The amount and currency of the payment. + """ + paymentAmount: MoneyInput! + + """ + A unique client generated key used to avoid duplicate charges. When a duplicate payment is found, the original is returned instead of creating a new one. + """ + idempotencyKey: String! + + """ + The billing address for the payment. + """ + billingAddress: MailingAddressInput! + + """ + A simple string or JSON containing the required payment data for the tokenized payment. + """ + paymentData: String! + + """ + Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`. + """ + test: Boolean + + """ + Public Hash Key used for AndroidPay payments only. + """ + identifier: String + + """ + The type of payment token. + """ + type: PaymentTokenType! +} + +""" +An object representing exchange of money for a product or service. +""" +type Transaction { + """ + The amount of money that the transaction was for. + """ + amount: Money! @deprecated(reason: "Use `amountV2` instead") + + """ + The amount of money that the transaction was for. + """ + amountV2: MoneyV2! + + """ + The kind of the transaction. + """ + kind: TransactionKind! + + """ + The status of the transaction. + """ + status: TransactionStatus! @deprecated(reason: "Use `statusV2` instead") + + """ + The status of the transaction. + """ + statusV2: TransactionStatus + + """ + Whether the transaction was done in test mode or not. + """ + test: Boolean! +} + +enum TransactionKind { + SALE + CAPTURE + AUTHORIZATION + EMV_AUTHORIZATION + CHANGE +} + +enum TransactionStatus { + PENDING + SUCCESS + FAILURE + ERROR +} + +""" +An RFC 3986 and RFC 3987 compliant URI string. + +Example value: `"https://johns-apparel.myshopify.com"`. +""" +scalar URL + +""" +The measurement used to calculate a unit price for a product variant (e.g. $9.99 / 100ml). +""" +type UnitPriceMeasurement { + """ + The type of unit of measurement for the unit price measurement. + """ + measuredType: UnitPriceMeasurementMeasuredType + + """ + The quantity unit for the unit price measurement. + """ + quantityUnit: UnitPriceMeasurementMeasuredUnit + + """ + The quantity value for the unit price measurement. + """ + quantityValue: Float! + + """ + The reference unit for the unit price measurement. + """ + referenceUnit: UnitPriceMeasurementMeasuredUnit + + """ + The reference value for the unit price measurement. + """ + referenceValue: Int! +} + +""" +The accepted types of unit of measurement. +""" +enum UnitPriceMeasurementMeasuredType { + """ + Unit of measurements representing volumes. + """ + VOLUME + + """ + Unit of measurements representing weights. + """ + WEIGHT + + """ + Unit of measurements representing lengths. + """ + LENGTH + + """ + Unit of measurements representing areas. + """ + AREA +} + +""" +The valid units of measurement for a unit price measurement. +""" +enum UnitPriceMeasurementMeasuredUnit { + """ + 1000 milliliters equals 1 liter. + """ + ML + + """ + 100 centiliters equals 1 liter. + """ + CL + + """ + Metric system unit of volume. + """ + L + + """ + 1 cubic meter equals 1000 liters. + """ + M3 + + """ + 1000 milligrams equals 1 gram. + """ + MG + + """ + Metric system unit of weight. + """ + G + + """ + 1 kilogram equals 1000 grams. + """ + KG + + """ + 1000 millimeters equals 1 meter. + """ + MM + + """ + 100 centimeters equals 1 meter. + """ + CM + + """ + Metric system unit of length. + """ + M + + """ + Metric system unit of area. + """ + M2 +} + +""" +Represents an error in the input of a mutation. +""" +type UserError implements DisplayableError { + """ + Path to the input field which caused the error. + """ + field: [String!] + + """ + The error message. + """ + message: String! +} + +""" +Represents a Shopify hosted video. +""" +type Video implements Node & Media { + """ + A word or phrase to share the nature or contents of a media. + """ + alt: String + + """ + Globally unique identifier. + """ + id: ID! + + """ + The media content type. + """ + mediaContentType: MediaContentType! + + """ + The preview image for the media. + """ + previewImage: Image + + """ + The sources for a video. + """ + sources: [VideoSource!]! +} + +""" +Represents a source for a Shopify hosted video. +""" +type VideoSource { + """ + The format of the video source. + """ + format: String! + + """ + The height of the video. + """ + height: Int! + + """ + The video MIME type. + """ + mimeType: String! + + """ + The URL of the video. + """ + url: String! + + """ + The width of the video. + """ + width: Int! +} + +""" +Units of measurement for weight. +""" +enum WeightUnit { + """ + 1 kilogram equals 1000 grams. + """ + KILOGRAMS + + """ + Metric system unit of mass. + """ + GRAMS + + """ + 1 pound equals 16 ounces. + """ + POUNDS + + """ + Imperial system unit of mass. + """ + OUNCES +} diff --git a/framework/swell/swell-js.d.ts b/framework/swell/swell-js.d.ts new file mode 100644 index 00000000..64a94d89 --- /dev/null +++ b/framework/swell/swell-js.d.ts @@ -0,0 +1 @@ +declare module 'swell-js' diff --git a/framework/swell/types.ts b/framework/swell/types.ts new file mode 100644 index 00000000..470f46c8 --- /dev/null +++ b/framework/swell/types.ts @@ -0,0 +1,123 @@ +import * as Core from '@commerce/types' +import { CheckoutLineItem } from './schema' + +export type SwellImage = { + file: { + url: String + height: Number + width: Number + } + id: string +} + +export type CartLineItem = { + id: string + product: SwellProduct + price: number + variant: { + name: string | null + sku: string | null + id: string + } + quantity: number +} + +export type SwellCart = { + id: string + account_id: number + currency: string + tax_included_total: number + sub_total: number + grand_total: number + discount_total: number + quantity: number + items: CartLineItem[] + date_created: string + discounts?: { id: number; amount: number }[] | null + // TODO: add missing fields +} + +export type SwellVariant = { + id: string + option_value_ids: string[] + name: string + price?: number + stock_status?: string +} + +export interface ProductOptionValue { + label: string + hexColors?: string[] + id: string +} + +export type ProductOptions = { + id: string + name: string + variant: boolean + values: ProductOptionValue[] + required: boolean + active: boolean + attribute_id: string +} + +export interface SwellProduct { + id: string + description: string + name: string + slug: string + currency: string + price: number + images: any[] + options: any[] + variants: any[] +} + +export interface SwellCustomer extends Core.Customer { + first_name: string + last_name: string +} + +export type SwellCheckout = { + id: string + webUrl: string + lineItems: CheckoutLineItem[] +} + +export interface Cart extends Core.Cart { + id: string + lineItems: LineItem[] +} + +export interface LineItem extends Core.LineItem { + options?: any[] +} + +/** + * Cart mutations + */ + +export type OptionSelections = { + option_id: number + option_value: number | string +} + +export type CartItemBody = Core.CartItemBody & { + productId: string // The product id is always required for BC + optionSelections?: OptionSelections +} + +export type GetCartHandlerBody = Core.GetCartHandlerBody + +export type AddCartItemBody = Core.AddCartItemBody<CartItemBody> + +export type AddCartItemHandlerBody = Core.AddCartItemHandlerBody<CartItemBody> + +export type UpdateCartItemBody = Core.UpdateCartItemBody<CartItemBody> + +export type UpdateCartItemHandlerBody = + Core.UpdateCartItemHandlerBody<CartItemBody> + +export type RemoveCartItemBody = Core.RemoveCartItemBody + +export type RemoveCartItemHandlerBody = Core.RemoveCartItemHandlerBody diff --git a/framework/swell/utils/customer-token.ts b/framework/swell/utils/customer-token.ts new file mode 100644 index 00000000..63bd51bc --- /dev/null +++ b/framework/swell/utils/customer-token.ts @@ -0,0 +1,21 @@ +import Cookies, { CookieAttributes } from 'js-cookie' +import { SWELL_COOKIE_EXPIRE, SWELL_CUSTOMER_TOKEN_COOKIE } from '../const' + +export const getCustomerToken = () => Cookies.get(SWELL_CUSTOMER_TOKEN_COOKIE) + +export const setCustomerToken = ( + token: string | null, + options?: CookieAttributes +) => { + if (!token) { + Cookies.remove(SWELL_CUSTOMER_TOKEN_COOKIE) + } else { + Cookies.set( + SWELL_CUSTOMER_TOKEN_COOKIE, + token, + options ?? { + expires: SWELL_COOKIE_EXPIRE, + } + ) + } +} diff --git a/framework/swell/utils/get-categories.ts b/framework/swell/utils/get-categories.ts new file mode 100644 index 00000000..4372dde4 --- /dev/null +++ b/framework/swell/utils/get-categories.ts @@ -0,0 +1,20 @@ +import { SwellConfig } from '../api' + +export type Category = { + entityId: string + name: string + path: string +} + +const getCategories = async (config: SwellConfig): Promise<Category[]> => { + const data = await config.fetch('categories', 'get') + return ( + data.results.map(({ id: entityId, name, slug }: any) => ({ + entityId, + name, + path: `/${slug}`, + })) ?? [] + ) +} + +export default getCategories diff --git a/framework/swell/utils/get-checkout-id.ts b/framework/swell/utils/get-checkout-id.ts new file mode 100644 index 00000000..07643f47 --- /dev/null +++ b/framework/swell/utils/get-checkout-id.ts @@ -0,0 +1,8 @@ +import Cookies from 'js-cookie' +import { SWELL_CHECKOUT_ID_COOKIE } from '../const' + +const getCheckoutId = (id?: string) => { + return id ?? Cookies.get(SWELL_CHECKOUT_ID_COOKIE) +} + +export default getCheckoutId diff --git a/framework/swell/utils/get-search-variables.ts b/framework/swell/utils/get-search-variables.ts new file mode 100644 index 00000000..c1b40ae5 --- /dev/null +++ b/framework/swell/utils/get-search-variables.ts @@ -0,0 +1,27 @@ +import getSortVariables from './get-sort-variables' +import type { SearchProductsInput } from '../product/use-search' + +export const getSearchVariables = ({ + brandId, + search, + categoryId, + sort, +}: SearchProductsInput) => { + let query = '' + + if (search) { + query += `product_type:${search} OR title:${search} OR tag:${search}` + } + + if (brandId) { + query += `${search ? ' AND ' : ''}vendor:${brandId}` + } + + return { + categoryId, + query, + ...getSortVariables(sort, !!categoryId), + } +} + +export default getSearchVariables diff --git a/framework/swell/utils/get-sort-variables.ts b/framework/swell/utils/get-sort-variables.ts new file mode 100644 index 00000000..b8cdeec5 --- /dev/null +++ b/framework/swell/utils/get-sort-variables.ts @@ -0,0 +1,32 @@ +const getSortVariables = (sort?: string, isCategory = false) => { + let output = {} + switch (sort) { + case 'price-asc': + output = { + sortKey: 'PRICE', + reverse: false, + } + break + case 'price-desc': + output = { + sortKey: 'PRICE', + reverse: true, + } + break + case 'trending-desc': + output = { + sortKey: 'BEST_SELLING', + reverse: false, + } + break + case 'latest-desc': + output = { + sortKey: isCategory ? 'CREATED' : 'CREATED_AT', + reverse: true, + } + break + } + return output +} + +export default getSortVariables diff --git a/framework/swell/utils/get-vendors.ts b/framework/swell/utils/get-vendors.ts new file mode 100644 index 00000000..1ede6883 --- /dev/null +++ b/framework/swell/utils/get-vendors.ts @@ -0,0 +1,27 @@ +import { SwellConfig } from '../api' + +export type BrandNode = { + name: string + path: string +} + +export type BrandEdge = { + node: BrandNode +} + +export type Brands = BrandEdge[] + +const getVendors = async (config: SwellConfig) => { + const vendors: [string] = + (await config.fetch('attributes', 'get', ['brand']))?.values ?? [] + + return [...new Set(vendors)].map((v) => ({ + node: { + entityId: v, + name: v, + path: `brands/${v}`, + }, + })) +} + +export default getVendors diff --git a/framework/swell/utils/handle-fetch-response.ts b/framework/swell/utils/handle-fetch-response.ts new file mode 100644 index 00000000..2688c9c7 --- /dev/null +++ b/framework/swell/utils/handle-fetch-response.ts @@ -0,0 +1,19 @@ +import { CommerceError } from '@commerce/utils/errors' + +type SwellFetchResponse = { + error: { + message: string + code?: string + } +} + +const handleFetchResponse = async (res: SwellFetchResponse) => { + if (res) { + if (res.error) { + throw new CommerceError(res.error) + } + return res + } +} + +export default handleFetchResponse diff --git a/framework/swell/utils/handle-login.ts b/framework/swell/utils/handle-login.ts new file mode 100644 index 00000000..77b6873e --- /dev/null +++ b/framework/swell/utils/handle-login.ts @@ -0,0 +1,39 @@ +import { ValidationError } from '@commerce/utils/errors' +import { setCustomerToken } from './customer-token' + +const getErrorMessage = ({ + code, + message, +}: { + code: string + message: string +}) => { + switch (code) { + case 'UNIDENTIFIED_CUSTOMER': + message = 'Cannot find an account that matches the provided credentials' + break + } + return message +} + +const handleLogin = (data: any) => { + const response = data.customerAccessTokenCreate + const errors = response?.customerUserErrors + + if (errors && errors.length) { + throw new ValidationError({ + message: getErrorMessage(errors[0]), + }) + } + + const customerAccessToken = response?.customerAccessToken + const accessToken = customerAccessToken?.accessToken + + if (accessToken) { + setCustomerToken(accessToken) + } + + return customerAccessToken +} + +export default handleLogin diff --git a/framework/swell/utils/index.ts b/framework/swell/utils/index.ts new file mode 100644 index 00000000..9ec81bfb --- /dev/null +++ b/framework/swell/utils/index.ts @@ -0,0 +1,9 @@ +export { default as handleFetchResponse } from './handle-fetch-response' +export { default as getSearchVariables } from './get-search-variables' +export { default as getSortVariables } from './get-sort-variables' +export { default as getVendors } from './get-vendors' +export { default as getCategories } from './get-categories' +export { default as getCheckoutId } from './get-checkout-id' + +export * from './normalize' +export * from './customer-token' diff --git a/framework/swell/utils/normalize.ts b/framework/swell/utils/normalize.ts new file mode 100644 index 00000000..b0cfb619 --- /dev/null +++ b/framework/swell/utils/normalize.ts @@ -0,0 +1,219 @@ +import { Product, Customer } from '@commerce/types' + +import { MoneyV2, ProductOption } from '../schema' + +import type { + Cart, + CartLineItem, + SwellCustomer, + SwellProduct, + SwellImage, + SwellVariant, + ProductOptionValue, + SwellCart, + LineItem, +} from '../types' + +const money = ({ amount, currencyCode }: MoneyV2) => { + return { + value: +amount, + currencyCode, + } +} + +type normalizedProductOption = { + __typename?: string + id: string + displayName: string + values: ProductOptionValue[] +} + +const normalizeProductOption = ({ + id, + name: displayName = '', + values = [], +}: ProductOption) => { + let returnValues = values.map((value) => { + let output: any = { + label: value.name, + id: value?.id || id, + } + if (displayName.match(/colou?r/gi)) { + output = { + ...output, + hexColors: [value.name], + } + } + return output + }) + return { + __typename: 'MultipleChoiceOption', + id, + displayName, + values: returnValues, + } +} + +const normalizeProductImages = (images: SwellImage[]) => { + if (!images || images.length < 1) { + return [{ url: '/' }] + } + return images?.map(({ file, ...rest }: SwellImage) => ({ + url: file?.url + '', + height: Number(file?.height), + width: Number(file?.width), + ...rest, + })) +} + +const normalizeProductVariants = ( + variants: SwellVariant[], + productOptions: normalizedProductOption[] +) => { + return variants?.map( + ({ id, name, price, option_value_ids: optionValueIds = [] }) => { + const values = name + .split(',') + .map((i) => ({ name: i.trim(), label: i.trim() })) + + const options = optionValueIds.map((id) => { + const matchingOption = productOptions.find((option) => { + return option.values.find( + (value: ProductOptionValue) => value.id == id + ) + }) + return normalizeProductOption({ + id, + name: matchingOption?.displayName ?? '', + values, + }) + }) + + return { + id, + name, + // sku: sku ?? id, + price: price ?? null, + listPrice: price ?? null, + // requiresShipping: true, + options, + } + } + ) +} + +export function normalizeProduct(swellProduct: SwellProduct): Product { + const { + id, + name, + description, + images, + options, + slug, + variants, + price: value, + currency: currencyCode, + } = swellProduct + // ProductView accesses variants for each product + const emptyVariants = [{ options: [], id, name }] + const productOptions = options + ? options.map((o) => normalizeProductOption(o)) + : [] + const productVariants = variants + ? normalizeProductVariants(variants, productOptions) + : [] + + const productImages = normalizeProductImages(images) + const product = { + ...swellProduct, + description, + id, + vendor: '', + path: `/${slug}`, + images: productImages, + variants: + productVariants && productVariants.length + ? productVariants + : emptyVariants, + options: productOptions, + price: { + value, + currencyCode, + }, + } + return product +} + +export function normalizeCart({ + id, + account_id, + date_created, + currency, + tax_included_total, + items, + sub_total, + grand_total, + discounts, +}: SwellCart) { + const cart: Cart = { + id: id, + customerId: account_id + '', + email: '', + createdAt: date_created, + currency: { code: currency }, + taxesIncluded: tax_included_total > 0, + lineItems: items?.map(normalizeLineItem) ?? [], + lineItemsSubtotalPrice: +sub_total, + subtotalPrice: +sub_total, + totalPrice: grand_total, + discounts: discounts?.map((discount) => ({ value: discount.amount })), + } + return cart +} + +export function normalizeCustomer(customer: SwellCustomer): Customer { + const { first_name: firstName, last_name: lastName } = customer + return { + ...customer, + firstName, + lastName, + } +} + +function normalizeLineItem({ + id, + product, + price, + variant, + quantity, +}: CartLineItem): LineItem { + const item = { + id, + variantId: variant?.id, + productId: product.id ?? '', + name: product?.name ?? '', + quantity, + variant: { + id: variant?.id ?? '', + sku: variant?.sku ?? '', + name: variant?.name!, + image: { + url: + product?.images && product.images.length > 0 + ? product?.images[0].file.url + : '/', + }, + requiresShipping: false, + price: price, + listPrice: price, + }, + path: '', + discounts: [], + options: [ + { + value: variant?.name, + }, + ], + } + return item +} diff --git a/framework/swell/utils/storage.ts b/framework/swell/utils/storage.ts new file mode 100644 index 00000000..d46dadb2 --- /dev/null +++ b/framework/swell/utils/storage.ts @@ -0,0 +1,13 @@ +export const getCheckoutIdFromStorage = (token: string) => { + if (window && window.sessionStorage) { + return window.sessionStorage.getItem(token) + } + + return null +} + +export const setCheckoutIdInStorage = (token: string, id: string | number) => { + if (window && window.sessionStorage) { + return window.sessionStorage.setItem(token, id + '') + } +} diff --git a/framework/swell/wishlist/use-add-item.tsx b/framework/swell/wishlist/use-add-item.tsx new file mode 100644 index 00000000..75f067c3 --- /dev/null +++ b/framework/swell/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/framework/swell/wishlist/use-remove-item.tsx b/framework/swell/wishlist/use-remove-item.tsx new file mode 100644 index 00000000..a2d3a8a0 --- /dev/null +++ b/framework/swell/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/framework/swell/wishlist/use-wishlist.tsx b/framework/swell/wishlist/use-wishlist.tsx new file mode 100644 index 00000000..cd1bfa0a --- /dev/null +++ b/framework/swell/wishlist/use-wishlist.tsx @@ -0,0 +1,46 @@ +// TODO: replace this hook and other wishlist hooks with a handler, or remove them if +// Swell doesn't have a wishlist + +import { HookFetcher } from '@commerce/utils/types' +import { Product } from '../schema' + +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<Wishlist | null, UseWishlistInput> = () => { + return null +} + +export function extendHook( + customFetcher: typeof fetcher, + // swrOptions?: SwrOptions<Wishlist | null, UseWishlistInput> + swrOptions?: any +) { + const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => { + return { data: null } + } + + useWishlist.extend = extendHook + + return useWishlist +} + +export default extendHook(fetcher) diff --git a/framework/vendure/.env.template b/framework/vendure/.env.template new file mode 100644 index 00000000..d8f7f14b --- /dev/null +++ b/framework/vendure/.env.template @@ -0,0 +1 @@ +NEXT_PUBLIC_VENDURE_SHOP_API_URL=http://localhost:3001/shop-api diff --git a/framework/vendure/README.md b/framework/vendure/README.md new file mode 100644 index 00000000..c1bcd7b5 --- /dev/null +++ b/framework/vendure/README.md @@ -0,0 +1,33 @@ +# Vendure Storefront Data Hooks + +UI hooks and data fetching methods built from the ground up for e-commerce applications written in React, that use [Vendure](http://vendure.io/) as a headless e-commerce platform. + +## Usage + +1. Clone this repo and install its dependencies with `yarn install` or `npm install` +2. Set the Vendure provider and API URL in your `.env.local` file: + ``` + COMMERCE_PROVIDER=vendure + NEXT_PUBLIC_VENDURE_SHOP_API_URL=https://demo.vendure.io/shop-api + NEXT_PUBLIC_VENDURE_LOCAL_URL=/vendure-shop-api + ``` +3. With the Vendure server running, start this project using `yarn dev` or `npm run dev`. + +## Known Limitations + +1. Vendure does not ship with built-in wishlist functionality. +2. Nor does it come with any kind of blog/page-building feature. Both of these can be created as Vendure plugins, however. +3. The entire Vendure customer flow is carried out via its GraphQL API. This means that there is no external, pre-existing checkout flow. The checkout flow must be created as part of the Next.js app. See https://github.com/vercel/commerce/issues/64 for further discusion. +4. By default, the sign-up flow in Vendure uses email verification. This means that using the existing "sign up" flow from this project will not grant a new user the ability to authenticate, since the new account must first be verified. Again, the necessary parts to support this flow can be created as part of the Next.js app. + +## Code generation + +This provider makes use of GraphQL code generation. The [schema.graphql](./schema.graphql) and [schema.d.ts](./schema.d.ts) files contain the generated types & schema introspection results. + +When developing the provider, changes to any GraphQL operations should be followed by re-generation of the types and schema files: + +From the project root dir, run + +```sh +graphql-codegen --config ./framework/vendure/codegen.json +``` diff --git a/framework/vendure/api/cart/index.ts b/framework/vendure/api/cart/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/vendure/api/cart/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/vendure/api/catalog/index.ts b/framework/vendure/api/catalog/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/vendure/api/catalog/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/vendure/api/catalog/products.ts b/framework/vendure/api/catalog/products.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/vendure/api/catalog/products.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/vendure/api/checkout/index.ts b/framework/vendure/api/checkout/index.ts new file mode 100644 index 00000000..21083e9b --- /dev/null +++ b/framework/vendure/api/checkout/index.ts @@ -0,0 +1,60 @@ +import { NextApiHandler } from 'next' + +const checkoutApi = async (req: any, res: any, config: any) => { + try { + const html = ` + <!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Checkout + + +
    +

    Checkout not implemented :(

    +

    + See #64 +

    +
    + + + ` + + res.status(200) + res.setHeader('Content-Type', 'text/html') + res.write(html) + res.end() + } catch (error) { + console.error(error) + + const message = 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +export function createApiHandler( + handler: any, + handlers: H, + defaultOptions: Options +) { + return function getApiHandler({ + config, + operations, + options, + }: { + config?: any + operations?: Partial + options?: Options extends {} ? Partial : never + } = {}): NextApiHandler { + const ops = { ...operations, ...handlers } + const opts = { ...defaultOptions, ...options } + + return function apiHandler(req, res) { + return handler(req, res, config, ops, opts) + } + } +} + +export default createApiHandler(checkoutApi, {}, {}) diff --git a/framework/vendure/api/customers/index.ts b/framework/vendure/api/customers/index.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/vendure/api/customers/index.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/vendure/api/customers/login.ts b/framework/vendure/api/customers/login.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/vendure/api/customers/login.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/vendure/api/customers/logout.ts b/framework/vendure/api/customers/logout.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/vendure/api/customers/logout.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/vendure/api/customers/signup.ts b/framework/vendure/api/customers/signup.ts new file mode 100644 index 00000000..ea9b101e --- /dev/null +++ b/framework/vendure/api/customers/signup.ts @@ -0,0 +1 @@ +export default function () {} diff --git a/framework/vendure/api/index.ts b/framework/vendure/api/index.ts new file mode 100644 index 00000000..f6b06a10 --- /dev/null +++ b/framework/vendure/api/index.ts @@ -0,0 +1,51 @@ +import type { CommerceAPIConfig } from '@commerce/api' +import fetchGraphqlApi from './utils/fetch-graphql-api' + +export interface VendureConfig extends CommerceAPIConfig {} + +const API_URL = process.env.NEXT_PUBLIC_VENDURE_SHOP_API_URL + +if (!API_URL) { + throw new Error( + `The environment variable NEXT_PUBLIC_VENDURE_SHOP_API_URL is missing and it's required to access your store` + ) +} + +export class Config { + private config: VendureConfig + + constructor(config: VendureConfig) { + this.config = { + ...config, + } + } + + getConfig(userConfig: Partial = {}) { + return Object.entries(userConfig).reduce( + (cfg, [key, value]) => Object.assign(cfg, { [key]: value }), + { ...this.config } + ) + } + + setConfig(newConfig: Partial) { + Object.assign(this.config, newConfig) + } +} + +const ONE_DAY = 60 * 60 * 24 +const config = new Config({ + commerceUrl: API_URL, + apiToken: '', + cartCookie: '', + customerCookie: '', + cartCookieMaxAge: ONE_DAY * 30, + fetch: fetchGraphqlApi, +}) + +export function getConfig(userConfig?: Partial) { + return config.getConfig(userConfig) +} + +export function setConfig(newConfig: Partial) { + return config.setConfig(newConfig) +} diff --git a/framework/vendure/api/utils/fetch-graphql-api.ts b/framework/vendure/api/utils/fetch-graphql-api.ts new file mode 100644 index 00000000..f769123e --- /dev/null +++ b/framework/vendure/api/utils/fetch-graphql-api.ts @@ -0,0 +1,37 @@ +import { FetcherError } from '@commerce/utils/errors' +import type { GraphQLFetcher } from '@commerce/api' +import { getConfig } from '..' +import fetch from './fetch' + +const fetchGraphqlApi: GraphQLFetcher = async ( + query: string, + { variables, preview } = {}, + fetchOptions +) => { + const config = getConfig() + const res = await fetch(config.commerceUrl, { + ...fetchOptions, + method: 'POST', + headers: { + Authorization: `Bearer ${config.apiToken}`, + ...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 Vendure API' }], + status: res.status, + }) + } + + return { data: json.data, res } +} + +export default fetchGraphqlApi diff --git a/framework/vendure/api/utils/fetch.ts b/framework/vendure/api/utils/fetch.ts new file mode 100644 index 00000000..9d9fff3e --- /dev/null +++ b/framework/vendure/api/utils/fetch.ts @@ -0,0 +1,3 @@ +import zeitFetch from '@vercel/fetch' + +export default zeitFetch() diff --git a/framework/vendure/api/wishlist/index.tsx b/framework/vendure/api/wishlist/index.tsx new file mode 100644 index 00000000..a7285667 --- /dev/null +++ b/framework/vendure/api/wishlist/index.tsx @@ -0,0 +1,2 @@ +export type WishlistItem = { product: any; id: number } +export default function () {} diff --git a/framework/vendure/auth/use-login.tsx b/framework/vendure/auth/use-login.tsx new file mode 100644 index 00000000..a63f0726 --- /dev/null +++ b/framework/vendure/auth/use-login.tsx @@ -0,0 +1,52 @@ +import { useCallback } from 'react' +import { MutationHook } from '@commerce/utils/types' +import useLogin, { UseLogin } from '@commerce/auth/use-login' +import { CommerceError, ValidationError } from '@commerce/utils/errors' +import useCustomer from '../customer/use-customer' +import { LoginMutation, LoginMutationVariables } from '../schema' +import { loginMutation } from '../lib/mutations/log-in-mutation' + +export default useLogin as UseLogin + +export const handler: MutationHook = { + fetchOptions: { + query: loginMutation, + }, + async fetcher({ input: { email, password }, options, fetch }) { + if (!(email && password)) { + throw new CommerceError({ + message: 'A email and password are required to login', + }) + } + + const variables: LoginMutationVariables = { + username: email, + password, + } + + const { login } = await fetch({ + ...options, + variables, + }) + + if (login.__typename !== 'CurrentUser') { + throw new ValidationError(login) + } + + return null + }, + useHook: + ({ fetch }) => + () => { + const { revalidate } = useCustomer() + + return useCallback( + async function login(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/vendure/auth/use-logout.tsx b/framework/vendure/auth/use-logout.tsx new file mode 100644 index 00000000..f57ef583 --- /dev/null +++ b/framework/vendure/auth/use-logout.tsx @@ -0,0 +1,34 @@ +import { useCallback } from 'react' +import { MutationHook } from '@commerce/utils/types' +import useLogout, { UseLogout } from '@commerce/auth/use-logout' +import useCustomer from '../customer/use-customer' +import { LogoutMutation } from '../schema' +import { logoutMutation } from '../lib/mutations/log-out-mutation' + +export default useLogout as UseLogout + +export const handler: MutationHook = { + fetchOptions: { + query: logoutMutation, + }, + async fetcher({ options, fetch }) { + await fetch({ + ...options, + }) + return null + }, + useHook: + ({ fetch }) => + () => { + const { mutate } = useCustomer() + + return useCallback( + async function logout() { + const data = await fetch() + await mutate(null, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/vendure/auth/use-signup.tsx b/framework/vendure/auth/use-signup.tsx new file mode 100644 index 00000000..883c4e0b --- /dev/null +++ b/framework/vendure/auth/use-signup.tsx @@ -0,0 +1,70 @@ +import { useCallback } from 'react' +import { MutationHook } from '@commerce/utils/types' +import { CommerceError, ValidationError } from '@commerce/utils/errors' +import useSignup, { UseSignup } from '@commerce/auth/use-signup' +import useCustomer from '../customer/use-customer' +import { + RegisterCustomerInput, + SignupMutation, + SignupMutationVariables, +} from '../schema' +import { signupMutation } from '../lib/mutations/sign-up-mutation' + +export default useSignup as UseSignup + +export type SignupInput = { + email: string + firstName: string + lastName: string + password: string +} + +export const handler: MutationHook = { + fetchOptions: { + query: signupMutation, + }, + async fetcher({ + input: { firstName, lastName, email, password }, + options, + fetch, + }) { + if (!(firstName && lastName && email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to signup', + }) + } + const variables: SignupMutationVariables = { + input: { + firstName, + lastName, + emailAddress: email, + password, + }, + } + const { registerCustomerAccount } = await fetch({ + ...options, + variables, + }) + + if (registerCustomerAccount.__typename !== 'Success') { + throw new ValidationError(registerCustomerAccount) + } + + return null + }, + useHook: + ({ fetch }) => + () => { + const { revalidate } = useCustomer() + + return useCallback( + async function signup(input) { + const data = await fetch({ input }) + await revalidate() + return data + }, + [fetch, revalidate] + ) + }, +} diff --git a/framework/vendure/cart/index.ts b/framework/vendure/cart/index.ts new file mode 100644 index 00000000..43c6db2b --- /dev/null +++ b/framework/vendure/cart/index.ts @@ -0,0 +1,5 @@ +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 useWishlistActions } from './use-cart-actions' +export { default as useUpdateItem } from './use-cart-actions' diff --git a/framework/vendure/cart/use-add-item.tsx b/framework/vendure/cart/use-add-item.tsx new file mode 100644 index 00000000..742d1b46 --- /dev/null +++ b/framework/vendure/cart/use-add-item.tsx @@ -0,0 +1,54 @@ +import { Cart, CartItemBody } from '@commerce/types' +import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' +import { CommerceError } from '@commerce/utils/errors' +import { MutationHook } from '@commerce/utils/types' +import { useCallback } from 'react' +import useCart from './use-cart' +import { AddItemToOrderMutation } from '../schema' +import { normalizeCart } from '../lib/normalize' +import { addItemToOrderMutation } from '../lib/mutations/add-item-to-order-mutation' + +export default useAddItem as UseAddItem + +export const handler: MutationHook = { + fetchOptions: { + query: addItemToOrderMutation, + }, + async fetcher({ input, options, fetch }) { + if ( + input.quantity && + (!Number.isInteger(input.quantity) || input.quantity! < 1) + ) { + throw new CommerceError({ + message: 'The item quantity has to be a valid integer greater than 0', + }) + } + + const { addItemToOrder } = await fetch({ + ...options, + variables: { + quantity: input.quantity || 1, + variantId: input.variantId, + }, + }) + + if (addItemToOrder.__typename === 'Order') { + return normalizeCart(addItemToOrder) + } + throw new CommerceError(addItemToOrder) + }, + useHook: + ({ fetch }) => + () => { + const { mutate } = useCart() + + return useCallback( + async function addItem(input) { + const data = await fetch({ input }) + await mutate(data, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/vendure/cart/use-cart-actions.tsx b/framework/vendure/cart/use-cart-actions.tsx new file mode 100644 index 00000000..abb4a998 --- /dev/null +++ b/framework/vendure/cart/use-cart-actions.tsx @@ -0,0 +1,13 @@ +import useAddItem from './use-add-item' +import useRemoveItem from './use-remove-item' +import useUpdateItem from './use-update-item' + +// This hook is probably not going to be used, but it's here +// to show how a commerce should be structuring it +export default function useCartActions() { + const addItem = useAddItem() + const updateItem = useUpdateItem() + const removeItem = useRemoveItem() + + return { addItem, updateItem, removeItem } +} diff --git a/framework/vendure/cart/use-cart.tsx b/framework/vendure/cart/use-cart.tsx new file mode 100644 index 00000000..e2e47298 --- /dev/null +++ b/framework/vendure/cart/use-cart.tsx @@ -0,0 +1,51 @@ +import { Cart } from '@commerce/types' +import { SWRHook } from '@commerce/utils/types' +import useCart, { FetchCartInput, UseCart } from '@commerce/cart/use-cart' +import { ActiveOrderQuery, CartFragment } from '../schema' +import { normalizeCart } from '../lib/normalize' +import { useMemo } from 'react' +import { getCartQuery } from '../lib/queries/get-cart-query' + +export type CartResult = { + activeOrder?: CartFragment + addItemToOrder?: CartFragment + adjustOrderLine?: CartFragment + removeOrderLine?: CartFragment +} + +export default useCart as UseCart + +export const handler: SWRHook< + Cart | null, + {}, + FetchCartInput, + { isEmpty?: boolean } +> = { + fetchOptions: { + query: getCartQuery, + }, + async fetcher({ input: { cartId }, options, fetch }) { + const { activeOrder } = await fetch(options) + return activeOrder ? normalizeCart(activeOrder) : null + }, + useHook: + ({ useData }) => + (input) => { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} diff --git a/framework/vendure/cart/use-remove-item.tsx b/framework/vendure/cart/use-remove-item.tsx new file mode 100644 index 00000000..deeb1bfd --- /dev/null +++ b/framework/vendure/cart/use-remove-item.tsx @@ -0,0 +1,48 @@ +import { useCallback } from 'react' +import { HookFetcherContext, MutationHookContext } from '@commerce/utils/types' +import useRemoveItem, { UseRemoveItem } from '@commerce/cart/use-remove-item' +import { CommerceError } from '@commerce/utils/errors' +import useCart from './use-cart' +import { + RemoveOrderLineMutation, + RemoveOrderLineMutationVariables, +} from '../schema' +import { Cart, LineItem, RemoveCartItemBody } from '@commerce/types' +import { normalizeCart } from '../lib/normalize' +import { removeOrderLineMutation } from '../lib/mutations/remove-order-line-mutation' + +export default useRemoveItem as UseRemoveItem + +export const handler = { + fetchOptions: { + query: removeOrderLineMutation, + }, + async fetcher({ input, options, fetch }: HookFetcherContext) { + const variables: RemoveOrderLineMutationVariables = { + orderLineId: input.id, + } + const { removeOrderLine } = await fetch({ + ...options, + variables, + }) + + if (removeOrderLine.__typename === 'Order') { + return normalizeCart(removeOrderLine) + } + throw new CommerceError(removeOrderLine) + }, + useHook: + ({ fetch }: MutationHookContext) => + (ctx = {}) => { + const { mutate } = useCart() + + return useCallback( + async function removeItem(input) { + const data = await fetch({ input }) + await mutate(data, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/vendure/cart/use-update-item.tsx b/framework/vendure/cart/use-update-item.tsx new file mode 100644 index 00000000..b0a160d1 --- /dev/null +++ b/framework/vendure/cart/use-update-item.tsx @@ -0,0 +1,80 @@ +import { useCallback } from 'react' +import { HookFetcherContext, MutationHookContext } from '@commerce/utils/types' +import { CommerceError, ValidationError } from '@commerce/utils/errors' +import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item' +import { + Cart, + CartItemBody, + LineItem, + UpdateCartItemBody, +} from '@commerce/types' +import useCart from './use-cart' +import { + AdjustOrderLineMutation, + AdjustOrderLineMutationVariables, +} from '../schema' +import { normalizeCart } from '../lib/normalize' +import { adjustOrderLineMutation } from '../lib/mutations/adjust-order-line-mutation' + +export default useUpdateItem as UseUpdateItem + +export const handler = { + fetchOptions: { + query: adjustOrderLineMutation, + }, + async fetcher(context: HookFetcherContext>) { + const { input, options, fetch } = context + const variables: AdjustOrderLineMutationVariables = { + quantity: input.item.quantity || 1, + orderLineId: input.itemId, + } + const { adjustOrderLine } = await fetch({ + ...options, + variables, + }) + + if (adjustOrderLine.__typename === 'Order') { + return normalizeCart(adjustOrderLine) + } + throw new CommerceError(adjustOrderLine) + }, + useHook: + ({ + fetch, + }: MutationHookContext>) => + ( + ctx: { + item?: LineItem + wait?: number + } = {} + ) => { + const { item } = ctx + const { mutate } = useCart() + + return useCallback( + async function addItem(input: Partial) { + const itemId = item?.id + const productId = input.productId ?? item?.productId + const variantId = input.productId ?? item?.variantId + if (!itemId || !productId || !variantId) { + throw new ValidationError({ + message: 'Invalid input used for this operation', + }) + } + const data = await fetch({ + input: { + item: { + productId, + variantId, + quantity: input.quantity, + }, + itemId, + }, + }) + await mutate(data, false) + return data + }, + [fetch, mutate] + ) + }, +} diff --git a/framework/vendure/codegen.json b/framework/vendure/codegen.json new file mode 100644 index 00000000..79a2b6ff --- /dev/null +++ b/framework/vendure/codegen.json @@ -0,0 +1,28 @@ +{ + "schema": { + "http://localhost:3001/shop-api": {} + }, + "documents": [ + { + "./framework/vendure/**/*.{ts,tsx}": { + "noRequire": true + } + } + ], + "generates": { + "./framework/vendure/schema.d.ts": { + "plugins": ["typescript", "typescript-operations"], + "config": { + "scalars": { + "ID": "string" + } + } + }, + "./framework/vendure/schema.graphql": { + "plugins": ["schema-ast"] + } + }, + "hooks": { + "afterAllFileWrite": ["prettier --write"] + } +} diff --git a/framework/vendure/commerce.config.json b/framework/vendure/commerce.config.json new file mode 100644 index 00000000..70806f06 --- /dev/null +++ b/framework/vendure/commerce.config.json @@ -0,0 +1,6 @@ +{ + "provider": "vendure", + "features": { + "wishlist": false + } +} diff --git a/framework/vendure/common/get-all-pages.ts b/framework/vendure/common/get-all-pages.ts new file mode 100644 index 00000000..e63f4281 --- /dev/null +++ b/framework/vendure/common/get-all-pages.ts @@ -0,0 +1,34 @@ +import { getConfig, VendureConfig } from '../api' + +export type Page = any + +export type GetAllPagesResult = + T + +async function getAllPages(opts?: { + config?: VendureConfig + preview?: boolean +}): Promise + +async function getAllPages(opts: { + url: string + config?: VendureConfig + preview?: boolean +}): Promise> + +async function getAllPages({ + config, + preview, +}: { + url?: string + config?: VendureConfig + preview?: boolean +} = {}): Promise { + config = getConfig(config) + + return { + pages: [], + } +} + +export default getAllPages diff --git a/framework/vendure/common/get-page.ts b/framework/vendure/common/get-page.ts new file mode 100644 index 00000000..48a18363 --- /dev/null +++ b/framework/vendure/common/get-page.ts @@ -0,0 +1,40 @@ +import { VendureConfig, getConfig } from '../api' + +export type Page = any + +export type GetPageResult = T + +export type PageVariables = { + id: number +} + +async function getPage(opts: { + url?: string + variables: PageVariables + config?: VendureConfig + preview?: boolean +}): Promise + +async function getPage(opts: { + url: string + variables: V + config?: VendureConfig + preview?: boolean +}): Promise> + +async function getPage({ + url, + variables, + config, + preview, +}: { + url?: string + variables: PageVariables + config?: VendureConfig + preview?: boolean +}): Promise { + config = getConfig(config) + return {} +} + +export default getPage diff --git a/framework/vendure/common/get-site-info.ts b/framework/vendure/common/get-site-info.ts new file mode 100644 index 00000000..9410c449 --- /dev/null +++ b/framework/vendure/common/get-site-info.ts @@ -0,0 +1,49 @@ +import { getConfig, VendureConfig } from '../api' +import { GetCollectionsQuery } from '../schema' +import { arrayToTree } from '../lib/array-to-tree' +import { getCollectionsQuery } from '../lib/queries/get-collections-query' + +export type Category = { + entityId: string + name: string + path: string + productCount: number +} + +export type GetSiteInfoResult< + T extends { categories: any[]; brands: any[] } = { + categories: Category[] + brands: any[] + } +> = T + +async function getSiteInfo({ + query = getCollectionsQuery, + variables, + config, +}: { + query?: string + variables?: any + config?: VendureConfig + preview?: boolean +} = {}): Promise { + config = getConfig(config) + // RecursivePartial forces the method to check for every prop in the data, which is + // required in case there's a custom `query` + const { data } = await config.fetch(query, { variables }) + const collections = data.collections?.items.map((i) => ({ + ...i, + entityId: i.id, + path: i.slug, + productCount: i.productVariants.totalItems, + })) + const categories = arrayToTree(collections).children + const brands = [] as any[] + + return { + categories: categories ?? [], + brands, + } +} + +export default getSiteInfo diff --git a/framework/vendure/customer/get-customer-wishlist.ts b/framework/vendure/customer/get-customer-wishlist.ts new file mode 100644 index 00000000..81ec9695 --- /dev/null +++ b/framework/vendure/customer/get-customer-wishlist.ts @@ -0,0 +1,18 @@ +import { getConfig, VendureConfig } from '../api' + +async function getCustomerWishlist({ + config, + variables, + includeProducts, +}: { + url?: string + variables: any + config?: VendureConfig + includeProducts?: boolean +}): Promise { + // Not implemented as Vendure does not ship with wishlist functionality at present + config = getConfig(config) + return { wishlist: {} } +} + +export default getCustomerWishlist diff --git a/framework/vendure/customer/index.ts b/framework/vendure/customer/index.ts new file mode 100644 index 00000000..6c903ecc --- /dev/null +++ b/framework/vendure/customer/index.ts @@ -0,0 +1 @@ +export { default as useCustomer } from './use-customer' diff --git a/framework/vendure/customer/use-customer.tsx b/framework/vendure/customer/use-customer.tsx new file mode 100644 index 00000000..ba198aa1 --- /dev/null +++ b/framework/vendure/customer/use-customer.tsx @@ -0,0 +1,35 @@ +import { SWRHook } from '@commerce/utils/types' +import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' +import { Customer } from '@commerce/types' +import { ActiveCustomerQuery } from '../schema' +import { activeCustomerQuery } from '../lib/queries/active-customer-query' + +export default useCustomer as UseCustomer + +export const handler: SWRHook = { + fetchOptions: { + query: activeCustomerQuery, + }, + async fetcher({ options, fetch }) { + const { activeCustomer } = await fetch({ + ...options, + }) + return activeCustomer + ? ({ + firstName: activeCustomer.firstName ?? '', + lastName: activeCustomer.lastName ?? '', + email: activeCustomer.emailAddress ?? '', + } as any) + : null + }, + useHook: + ({ useData }) => + (input) => { + return useData({ + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions, + }, + }) + }, +} diff --git a/framework/vendure/fetcher.ts b/framework/vendure/fetcher.ts new file mode 100644 index 00000000..bf8f0dcd --- /dev/null +++ b/framework/vendure/fetcher.ts @@ -0,0 +1,51 @@ +import { Fetcher } from '@commerce/utils/types' +import { FetcherError } from '@commerce/utils/errors' + +async function getText(res: Response) { + try { + return (await res.text()) || res.statusText + } catch (error) { + return res.statusText + } +} + +async function getError(res: Response) { + if (res.headers.get('Content-Type')?.includes('application/json')) { + const data = await res.json() + return new FetcherError({ errors: data.errors, status: res.status }) + } + return new FetcherError({ message: await getText(res), status: res.status }) +} + +export const fetcher: Fetcher = async ({ + url, + method = 'POST', + variables, + query, + body: bodyObj, +}) => { + const shopApiUrl = + process.env.NEXT_PUBLIC_VENDURE_LOCAL_URL || + process.env.NEXT_PUBLIC_VENDURE_SHOP_API_URL + if (!shopApiUrl) { + throw new Error( + 'The Vendure Shop API url has not been provided. Please define NEXT_PUBLIC_VENDURE_SHOP_API_URL in .env.local' + ) + } + const hasBody = Boolean(variables || query) + const body = hasBody ? JSON.stringify({ query, variables }) : undefined + const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined + const res = await fetch(shopApiUrl, { + method, + body, + headers, + credentials: 'include', + }) + + if (res.ok) { + const { data } = await res.json() + return data + } + + throw await getError(res) +} diff --git a/framework/vendure/index.tsx b/framework/vendure/index.tsx new file mode 100644 index 00000000..47e60c7d --- /dev/null +++ b/framework/vendure/index.tsx @@ -0,0 +1,33 @@ +import * as React from 'react' +import { ReactNode } from 'react' +import { + CommerceConfig, + CommerceProvider as CoreCommerceProvider, + useCommerce as useCoreCommerce, +} from '@commerce' +import { vendureProvider } from './provider' + +export const vendureConfig: CommerceConfig = { + locale: 'en-us', + cartCookie: 'session', +} + +export type VendureConfig = Partial + +export type VendureProps = { + children?: ReactNode + locale: string +} & VendureConfig + +export function CommerceProvider({ children, ...config }: VendureProps) { + return ( + + {children} + + ) +} + +export const useCommerce = () => useCoreCommerce() diff --git a/framework/vendure/lib/array-to-tree.ts b/framework/vendure/lib/array-to-tree.ts new file mode 100644 index 00000000..403cf226 --- /dev/null +++ b/framework/vendure/lib/array-to-tree.ts @@ -0,0 +1,67 @@ +export type HasParent = { id: string; parent?: { id: string } | null } +export type TreeNode = T & { + children: Array> + expanded: boolean +} +export type RootNode = { + id?: string + children: Array> +} + +export function arrayToTree( + nodes: T[], + currentState?: RootNode +): RootNode { + const topLevelNodes: Array> = [] + const mappedArr: { [id: string]: TreeNode } = {} + const currentStateMap = treeToMap(currentState) + + // First map the nodes of the array to an object -> create a hash table. + for (const node of nodes) { + mappedArr[node.id] = { ...(node as any), children: [] } + } + + for (const id of nodes.map((n) => n.id)) { + if (mappedArr.hasOwnProperty(id)) { + const mappedElem = mappedArr[id] + mappedElem.expanded = currentStateMap.get(id)?.expanded ?? false + const parent = mappedElem.parent + if (!parent) { + continue + } + // If the element is not at the root level, add it to its parent array of children. + const parentIsRoot = !mappedArr[parent.id] + if (!parentIsRoot) { + if (mappedArr[parent.id]) { + mappedArr[parent.id].children.push(mappedElem) + } else { + mappedArr[parent.id] = { children: [mappedElem] } as any + } + } else { + topLevelNodes.push(mappedElem) + } + } + } + // tslint:disable-next-line:no-non-null-assertion + const rootId = topLevelNodes.length ? topLevelNodes[0].parent!.id : undefined + return { id: rootId, children: topLevelNodes } +} + +/** + * Converts an existing tree (as generated by the arrayToTree function) into a flat + * Map. This is used to persist certain states (e.g. `expanded`) when re-building the + * tree. + */ +function treeToMap( + tree?: RootNode +): Map> { + const nodeMap = new Map>() + function visit(node: TreeNode) { + nodeMap.set(node.id, node) + node.children.forEach(visit) + } + if (tree) { + visit(tree as TreeNode) + } + return nodeMap +} diff --git a/framework/vendure/lib/fragments/cart-fragment.ts b/framework/vendure/lib/fragments/cart-fragment.ts new file mode 100644 index 00000000..36371e07 --- /dev/null +++ b/framework/vendure/lib/fragments/cart-fragment.ts @@ -0,0 +1,42 @@ +export const cartFragment = /* GraphQL */ ` + fragment Cart on Order { + id + code + createdAt + totalQuantity + subTotal + subTotalWithTax + total + totalWithTax + currencyCode + customer { + id + } + lines { + id + quantity + linePriceWithTax + discountedLinePriceWithTax + featuredAsset { + id + preview + } + discounts { + description + amount + } + productVariant { + id + name + sku + price + priceWithTax + stockLevel + product { + slug + } + productId + } + } + } +` diff --git a/framework/vendure/lib/fragments/search-result-fragment.ts b/framework/vendure/lib/fragments/search-result-fragment.ts new file mode 100644 index 00000000..6155b5b4 --- /dev/null +++ b/framework/vendure/lib/fragments/search-result-fragment.ts @@ -0,0 +1,24 @@ +export const searchResultFragment = /* GraphQL */ ` + fragment SearchResult on SearchResult { + productId + productName + description + description + slug + sku + currencyCode + productAsset { + id + preview + } + priceWithTax { + ... on SinglePrice { + value + } + ... on PriceRange { + min + max + } + } + } +` diff --git a/framework/vendure/lib/mutations/add-item-to-order-mutation.ts b/framework/vendure/lib/mutations/add-item-to-order-mutation.ts new file mode 100644 index 00000000..5ed41d97 --- /dev/null +++ b/framework/vendure/lib/mutations/add-item-to-order-mutation.ts @@ -0,0 +1,15 @@ +import { cartFragment } from '../fragments/cart-fragment' + +export const addItemToOrderMutation = /* GraphQL */ ` + mutation addItemToOrder($variantId: ID!, $quantity: Int!) { + addItemToOrder(productVariantId: $variantId, quantity: $quantity) { + __typename + ...Cart + ... on ErrorResult { + errorCode + message + } + } + } + ${cartFragment} +` diff --git a/framework/vendure/lib/mutations/adjust-order-line-mutation.ts b/framework/vendure/lib/mutations/adjust-order-line-mutation.ts new file mode 100644 index 00000000..ce9864b1 --- /dev/null +++ b/framework/vendure/lib/mutations/adjust-order-line-mutation.ts @@ -0,0 +1,15 @@ +import { cartFragment } from '../fragments/cart-fragment' + +export const adjustOrderLineMutation = /* GraphQL */ ` + mutation adjustOrderLine($orderLineId: ID!, $quantity: Int!) { + adjustOrderLine(orderLineId: $orderLineId, quantity: $quantity) { + __typename + ...Cart + ... on ErrorResult { + errorCode + message + } + } + } + ${cartFragment} +` diff --git a/framework/vendure/lib/mutations/log-in-mutation.ts b/framework/vendure/lib/mutations/log-in-mutation.ts new file mode 100644 index 00000000..75e2ddba --- /dev/null +++ b/framework/vendure/lib/mutations/log-in-mutation.ts @@ -0,0 +1,14 @@ +export const loginMutation = /* GraphQL */ ` + mutation login($username: String!, $password: String!) { + login(username: $username, password: $password) { + __typename + ... on CurrentUser { + id + } + ... on ErrorResult { + errorCode + message + } + } + } +` diff --git a/framework/vendure/lib/mutations/log-out-mutation.ts b/framework/vendure/lib/mutations/log-out-mutation.ts new file mode 100644 index 00000000..6f222c5c --- /dev/null +++ b/framework/vendure/lib/mutations/log-out-mutation.ts @@ -0,0 +1,7 @@ +export const logoutMutation = /* GraphQL */ ` + mutation logout { + logout { + success + } + } +` diff --git a/framework/vendure/lib/mutations/remove-order-line-mutation.ts b/framework/vendure/lib/mutations/remove-order-line-mutation.ts new file mode 100644 index 00000000..47a89039 --- /dev/null +++ b/framework/vendure/lib/mutations/remove-order-line-mutation.ts @@ -0,0 +1,15 @@ +import { cartFragment } from '../fragments/cart-fragment' + +export const removeOrderLineMutation = /* GraphQL */ ` + mutation removeOrderLine($orderLineId: ID!) { + removeOrderLine(orderLineId: $orderLineId) { + __typename + ...Cart + ... on ErrorResult { + errorCode + message + } + } + } + ${cartFragment} +` diff --git a/framework/vendure/lib/mutations/sign-up-mutation.ts b/framework/vendure/lib/mutations/sign-up-mutation.ts new file mode 100644 index 00000000..410e395c --- /dev/null +++ b/framework/vendure/lib/mutations/sign-up-mutation.ts @@ -0,0 +1,14 @@ +export const signupMutation = /* GraphQL */ ` + mutation signup($input: RegisterCustomerInput!) { + registerCustomerAccount(input: $input) { + __typename + ... on Success { + success + } + ... on ErrorResult { + errorCode + message + } + } + } +` diff --git a/framework/vendure/lib/normalize.ts b/framework/vendure/lib/normalize.ts new file mode 100644 index 00000000..c64ff213 --- /dev/null +++ b/framework/vendure/lib/normalize.ts @@ -0,0 +1,55 @@ +import { Cart, Product } from '@commerce/types' +import { CartFragment, SearchResultFragment } from '../schema' + +export function normalizeSearchResult(item: SearchResultFragment): Product { + return { + id: item.productId, + name: item.productName, + description: item.description, + slug: item.slug, + path: item.slug, + images: [{ url: item.productAsset?.preview + '?w=800&mode=crop' || '' }], + variants: [], + price: { + value: (item.priceWithTax as any).min / 100, + currencyCode: item.currencyCode, + }, + options: [], + sku: item.sku, + } +} + +export function normalizeCart(order: CartFragment): Cart { + return { + id: order.id.toString(), + createdAt: order.createdAt, + taxesIncluded: true, + lineItemsSubtotalPrice: order.subTotalWithTax / 100, + currency: { code: order.currencyCode }, + subtotalPrice: order.subTotalWithTax / 100, + totalPrice: order.totalWithTax / 100, + customerId: order.customer?.id, + lineItems: order.lines?.map((l) => ({ + id: l.id, + name: l.productVariant.name, + quantity: l.quantity, + url: l.productVariant.product.slug, + variantId: l.productVariant.id, + productId: l.productVariant.productId, + images: [{ url: l.featuredAsset?.preview + '?preset=thumb' || '' }], + discounts: l.discounts.map((d) => ({ value: d.amount / 100 })), + path: '', + variant: { + id: l.productVariant.id, + name: l.productVariant.name, + sku: l.productVariant.sku, + price: l.discountedLinePriceWithTax / 100, + listPrice: l.linePriceWithTax / 100, + image: { + url: l.featuredAsset?.preview + '?preset=thumb' || '', + }, + requiresShipping: true, + }, + })), + } +} diff --git a/framework/vendure/lib/queries/active-customer-query.ts b/framework/vendure/lib/queries/active-customer-query.ts new file mode 100644 index 00000000..65b28074 --- /dev/null +++ b/framework/vendure/lib/queries/active-customer-query.ts @@ -0,0 +1,10 @@ +export const activeCustomerQuery = /* GraphQL */ ` + query activeCustomer { + activeCustomer { + id + firstName + lastName + emailAddress + } + } +` diff --git a/framework/vendure/lib/queries/get-all-product-paths-query.ts b/framework/vendure/lib/queries/get-all-product-paths-query.ts new file mode 100644 index 00000000..29922dca --- /dev/null +++ b/framework/vendure/lib/queries/get-all-product-paths-query.ts @@ -0,0 +1,9 @@ +export const getAllProductPathsQuery = /* GraphQL */ ` + query getAllProductPaths($first: Int = 100) { + products(options: { take: $first }) { + items { + slug + } + } + } +` diff --git a/framework/vendure/lib/queries/get-all-products-query.ts b/framework/vendure/lib/queries/get-all-products-query.ts new file mode 100644 index 00000000..1b44b201 --- /dev/null +++ b/framework/vendure/lib/queries/get-all-products-query.ts @@ -0,0 +1,12 @@ +import { searchResultFragment } from '../fragments/search-result-fragment' + +export const getAllProductsQuery = /* GraphQL */ ` + query getAllProducts($input: SearchInput!) { + search(input: $input) { + items { + ...SearchResult + } + } + } + ${searchResultFragment} +` diff --git a/framework/vendure/lib/queries/get-cart-query.ts b/framework/vendure/lib/queries/get-cart-query.ts new file mode 100644 index 00000000..7faac355 --- /dev/null +++ b/framework/vendure/lib/queries/get-cart-query.ts @@ -0,0 +1,10 @@ +import { cartFragment } from '../fragments/cart-fragment' + +export const getCartQuery = /* GraphQL */ ` + query activeOrder { + activeOrder { + ...Cart + } + } + ${cartFragment} +` diff --git a/framework/vendure/lib/queries/get-collections-query.ts b/framework/vendure/lib/queries/get-collections-query.ts new file mode 100644 index 00000000..ed091965 --- /dev/null +++ b/framework/vendure/lib/queries/get-collections-query.ts @@ -0,0 +1,21 @@ +export const getCollectionsQuery = /* GraphQL */ ` + query getCollections { + collections { + items { + id + name + description + slug + productVariants { + totalItems + } + parent { + id + } + children { + id + } + } + } + } +` diff --git a/framework/vendure/lib/queries/get-product-query.ts b/framework/vendure/lib/queries/get-product-query.ts new file mode 100644 index 00000000..b2c502da --- /dev/null +++ b/framework/vendure/lib/queries/get-product-query.ts @@ -0,0 +1,41 @@ +export const getProductQuery = /* GraphQL */ ` + query getProduct($slug: String!) { + product(slug: $slug) { + id + name + slug + description + assets { + id + preview + name + } + variants { + id + priceWithTax + currencyCode + options { + id + name + code + groupId + group { + id + options { + name + } + } + } + } + optionGroups { + id + code + name + options { + id + name + } + } + } + } +` diff --git a/framework/vendure/lib/queries/search-query.ts b/framework/vendure/lib/queries/search-query.ts new file mode 100644 index 00000000..f95c4370 --- /dev/null +++ b/framework/vendure/lib/queries/search-query.ts @@ -0,0 +1,13 @@ +import { searchResultFragment } from '../fragments/search-result-fragment' + +export const searchQuery = /* GraphQL */ ` + query search($input: SearchInput!) { + search(input: $input) { + items { + ...SearchResult + } + totalItems + } + } + ${searchResultFragment} +` diff --git a/framework/vendure/next.config.js b/framework/vendure/next.config.js new file mode 100644 index 00000000..96153ad1 --- /dev/null +++ b/framework/vendure/next.config.js @@ -0,0 +1,8 @@ +const commerce = require('./commerce.config.json') + +module.exports = { + commerce, + images: { + domains: ['localhost', 'demo.vendure.io'], + }, +} diff --git a/framework/vendure/product/get-all-product-paths.ts b/framework/vendure/product/get-all-product-paths.ts new file mode 100644 index 00000000..dfbaff1b --- /dev/null +++ b/framework/vendure/product/get-all-product-paths.ts @@ -0,0 +1,48 @@ +import type { + GetAllProductPathsQuery, + GetAllProductPathsQueryVariables, +} from '../schema' +import { getConfig, VendureConfig } from '../api' +import { getAllProductPathsQuery } from '../lib/queries/get-all-product-paths-query' + +export type GetAllProductPathsResult = { + products: Array<{ node: { path: string } }> +} + +async function getAllProductPaths(opts?: { + variables?: GetAllProductPathsQueryVariables + config?: VendureConfig +}): Promise + +async function getAllProductPaths< + T extends { products: any[] }, + V = any +>(opts: { + query: string + variables?: V + config?: VendureConfig +}): Promise + +async function getAllProductPaths({ + query = getAllProductPathsQuery, + variables, + config, +}: { + query?: string + variables?: GetAllProductPathsQueryVariables + config?: VendureConfig +} = {}): Promise { + config = getConfig(config) + // RecursivePartial forces the method to check for every prop in the data, which is + // required in case there's a custom `query` + const { data } = await config.fetch(query, { + variables, + }) + const products = data.products.items + + return { + products: products.map((p) => ({ node: { path: `/${p.slug}` } })), + } +} + +export default getAllProductPaths diff --git a/framework/vendure/product/get-all-products.ts b/framework/vendure/product/get-all-products.ts new file mode 100644 index 00000000..b292e024 --- /dev/null +++ b/framework/vendure/product/get-all-products.ts @@ -0,0 +1,39 @@ +import { Product } from '@commerce/types' +import { getConfig, VendureConfig } from '../api' +import { GetAllProductsQuery } from '../schema' +import { normalizeSearchResult } from '../lib/normalize' +import { getAllProductsQuery } from '../lib/queries/get-all-products-query' + +export type ProductVariables = { first?: number } + +async function getAllProducts(opts?: { + variables?: ProductVariables + config?: VendureConfig + preview?: boolean +}): Promise<{ products: Product[] }> + +async function getAllProducts({ + query = getAllProductsQuery, + variables: { ...vars } = {}, + config, +}: { + query?: string + variables?: ProductVariables + config?: VendureConfig + preview?: boolean +} = {}): Promise<{ products: Product[] | any[] }> { + config = getConfig(config) + const variables = { + input: { + take: vars.first, + groupByProduct: true, + }, + } + const { data } = await config.fetch(query, { variables }) + + return { + products: data.search.items.map((item) => normalizeSearchResult(item)), + } +} + +export default getAllProducts diff --git a/framework/vendure/product/get-product.ts b/framework/vendure/product/get-product.ts new file mode 100644 index 00000000..735164ec --- /dev/null +++ b/framework/vendure/product/get-product.ts @@ -0,0 +1,57 @@ +import { Product } from '@commerce/types' +import { getConfig, VendureConfig } from '../api' +import { GetProductQuery } from '../schema' +import { getProductQuery } from '../lib/queries/get-product-query' + +async function getProduct({ + query = getProductQuery, + variables, + config, +}: { + query?: string + variables: { slug: string } + config?: VendureConfig + preview?: boolean +}): Promise { + config = getConfig(config) + + const locale = config.locale + const { data } = await config.fetch(query, { variables }) + const product = data.product + + if (product) { + return { + product: { + id: product.id, + name: product.name, + description: product.description, + slug: product.slug, + images: product.assets.map((a) => ({ + url: a.preview, + alt: a.name, + })), + variants: product.variants.map((v) => ({ + id: v.id, + options: v.options.map((o) => ({ + id: o.id, + displayName: o.name, + values: o.group.options.map((_o) => ({ label: _o.name })), + })), + })), + price: { + value: product.variants[0].priceWithTax / 100, + currencyCode: product.variants[0].currencyCode, + }, + options: product.optionGroups.map((og) => ({ + id: og.id, + displayName: og.name, + values: og.options.map((o) => ({ label: o.name })), + })), + } as Product, + } + } + + return {} +} + +export default getProduct diff --git a/framework/vendure/product/index.ts b/framework/vendure/product/index.ts new file mode 100644 index 00000000..b290c189 --- /dev/null +++ b/framework/vendure/product/index.ts @@ -0,0 +1,4 @@ +export { default as usePrice } from './use-price' +export { default as useSearch } from './use-search' +export { default as getProduct } from './get-product' +export { default as getAllProducts } from './get-all-products' diff --git a/framework/vendure/product/use-price.tsx b/framework/vendure/product/use-price.tsx new file mode 100644 index 00000000..0174faf5 --- /dev/null +++ b/framework/vendure/product/use-price.tsx @@ -0,0 +1,2 @@ +export * from '@commerce/product/use-price' +export { default } from '@commerce/product/use-price' diff --git a/framework/vendure/product/use-search.tsx b/framework/vendure/product/use-search.tsx new file mode 100644 index 00000000..5b7f7f43 --- /dev/null +++ b/framework/vendure/product/use-search.tsx @@ -0,0 +1,67 @@ +import { SWRHook } from '@commerce/utils/types' +import useSearch, { UseSearch } from '@commerce/product/use-search' +import { Product } from '@commerce/types' +import { SearchQuery, SearchQueryVariables } from '../schema' +import { normalizeSearchResult } from '../lib/normalize' +import { searchQuery } from '../lib/queries/search-query' + +export default useSearch as UseSearch + +export type SearchProductsInput = { + search?: string + categoryId?: string + brandId?: string + sort?: string +} + +export type SearchProductsData = { + products: Product[] + found: boolean +} + +export const handler: SWRHook< + SearchProductsData, + SearchProductsInput, + SearchProductsInput +> = { + fetchOptions: { + query: searchQuery, + }, + async fetcher({ input, options, fetch }) { + const { categoryId, brandId } = input + + const variables: SearchQueryVariables = { + input: { + term: input.search, + collectionId: input.categoryId, + groupByProduct: true, + // TODO: what is the "sort" value? + }, + } + const { search } = await fetch({ + query: searchQuery, + variables, + }) + + return { + found: search.totalItems > 0, + products: search.items.map((item) => normalizeSearchResult(item)) ?? [], + } + }, + 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/framework/vendure/provider.ts b/framework/vendure/provider.ts new file mode 100644 index 00000000..e100c277 --- /dev/null +++ b/framework/vendure/provider.ts @@ -0,0 +1,21 @@ +import { Provider } from '@commerce' +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' +import { fetcher } from './fetcher' + +export const vendureProvider: Provider = { + locale: 'en-us', + cartCookie: 'session', + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, +} diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts new file mode 100644 index 00000000..78e82125 --- /dev/null +++ b/framework/vendure/schema.d.ts @@ -0,0 +1,3122 @@ +export type Maybe = T | null +export type Exact = { + [K in keyof T]: T[K] +} +export type MakeOptional = Omit & + { [SubKey in K]?: Maybe } +export type MakeMaybe = Omit & + { [SubKey in K]: Maybe } +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string + String: string + Boolean: boolean + Int: number + Float: number + /** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ + JSON: any + /** A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. */ + DateTime: any + /** The `Upload` scalar type represents a file upload. */ + Upload: any +} + +export type Query = { + __typename?: 'Query' + /** The active Channel */ + activeChannel: Channel + /** The active Customer */ + activeCustomer?: Maybe + /** + * The active Order. Will be `null` until an Order is created via `addItemToOrder`. Once an Order reaches the + * state of `PaymentApproved` or `PaymentSettled`, then that Order is no longer considered "active" and this + * query will once again return `null`. + */ + activeOrder?: Maybe + /** An array of supported Countries */ + availableCountries: Array + /** A list of Collections available to the shop */ + collections: CollectionList + /** Returns a Collection either by its id or slug. If neither 'id' nor 'slug' is speicified, an error will result. */ + collection?: Maybe + /** Returns a list of eligible shipping methods based on the current active Order */ + eligibleShippingMethods: Array + /** Returns a list of payment methods and their eligibility based on the current active Order */ + eligiblePaymentMethods: Array + /** Returns information about the current authenticated User */ + me?: Maybe + /** Returns the possible next states that the activeOrder can transition to */ + nextOrderStates: Array + /** + * Returns an Order based on the id. Note that in the Shop API, only orders belonging to the + * currently-authenticated User may be queried. + */ + order?: Maybe + /** + * Returns an Order based on the order `code`. For guest Orders (i.e. Orders placed by non-authenticated Customers) + * this query will only return the Order within 2 hours of the Order being placed. This allows an Order confirmation + * screen to be shown immediately after completion of a guest checkout, yet prevents security risks of allowing + * general anonymous access to Order data. + */ + orderByCode?: Maybe + /** Get a Product either by id or slug. If neither 'id' nor 'slug' is speicified, an error will result. */ + product?: Maybe + /** Get a list of Products */ + products: ProductList + /** Search Products based on the criteria set by the `SearchInput` */ + search: SearchResponse +} + +export type QueryCollectionsArgs = { + options?: Maybe +} + +export type QueryCollectionArgs = { + id?: Maybe + slug?: Maybe +} + +export type QueryOrderArgs = { + id: Scalars['ID'] +} + +export type QueryOrderByCodeArgs = { + code: Scalars['String'] +} + +export type QueryProductArgs = { + id?: Maybe + slug?: Maybe +} + +export type QueryProductsArgs = { + options?: Maybe +} + +export type QuerySearchArgs = { + input: SearchInput +} + +export type Mutation = { + __typename?: 'Mutation' + /** Adds an item to the order. If custom fields are defined on the OrderLine entity, a third argument 'customFields' will be available. */ + addItemToOrder: UpdateOrderItemsResult + /** Remove an OrderLine from the Order */ + removeOrderLine: RemoveOrderItemsResult + /** Remove all OrderLine from the Order */ + removeAllOrderLines: RemoveOrderItemsResult + /** Adjusts an OrderLine. If custom fields are defined on the OrderLine entity, a third argument 'customFields' of type `OrderLineCustomFieldsInput` will be available. */ + adjustOrderLine: UpdateOrderItemsResult + /** Applies the given coupon code to the active Order */ + applyCouponCode: ApplyCouponCodeResult + /** Removes the given coupon code from the active Order */ + removeCouponCode?: Maybe + /** Transitions an Order to a new state. Valid next states can be found by querying `nextOrderStates` */ + transitionOrderToState?: Maybe + /** Sets the shipping address for this order */ + setOrderShippingAddress: ActiveOrderResult + /** Sets the billing address for this order */ + setOrderBillingAddress: ActiveOrderResult + /** Allows any custom fields to be set for the active order */ + setOrderCustomFields: ActiveOrderResult + /** Sets the shipping method by id, which can be obtained with the `eligibleShippingMethods` query */ + setOrderShippingMethod: SetOrderShippingMethodResult + /** Add a Payment to the Order */ + addPaymentToOrder: AddPaymentToOrderResult + /** Set the Customer for the Order. Required only if the Customer is not currently logged in */ + setCustomerForOrder: SetCustomerForOrderResult + /** Authenticates the user using the native authentication strategy. This mutation is an alias for `authenticate({ native: { ... }})` */ + login: NativeAuthenticationResult + /** Authenticates the user using a named authentication strategy */ + authenticate: AuthenticationResult + /** End the current authenticated session */ + logout: Success + /** + * Register a Customer account with the given credentials. There are three possible registration flows: + * + * _If `authOptions.requireVerification` is set to `true`:_ + * + * 1. **The Customer is registered _with_ a password**. A verificationToken will be created (and typically emailed to the Customer). That + * verificationToken would then be passed to the `verifyCustomerAccount` mutation _without_ a password. The Customer is then + * verified and authenticated in one step. + * 2. **The Customer is registered _without_ a password**. A verificationToken will be created (and typically emailed to the Customer). That + * verificationToken would then be passed to the `verifyCustomerAccount` mutation _with_ the chosed password of the Customer. The Customer is then + * verified and authenticated in one step. + * + * _If `authOptions.requireVerification` is set to `false`:_ + * + * 3. The Customer _must_ be registered _with_ a password. No further action is needed - the Customer is able to authenticate immediately. + */ + registerCustomerAccount: RegisterCustomerAccountResult + /** Regenerate and send a verification token for a new Customer registration. Only applicable if `authOptions.requireVerification` is set to true. */ + refreshCustomerVerification: RefreshCustomerVerificationResult + /** Update an existing Customer */ + updateCustomer: Customer + /** Create a new Customer Address */ + createCustomerAddress: Address + /** Update an existing Address */ + updateCustomerAddress: Address + /** Delete an existing Address */ + deleteCustomerAddress: Success + /** + * Verify a Customer email address with the token sent to that address. Only applicable if `authOptions.requireVerification` is set to true. + * + * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the a password _must_ be + * provided here. + */ + verifyCustomerAccount: VerifyCustomerAccountResult + /** Update the password of the active Customer */ + updateCustomerPassword: UpdateCustomerPasswordResult + /** + * Request to update the emailAddress of the active Customer. If `authOptions.requireVerification` is enabled + * (as is the default), then the `identifierChangeToken` will be assigned to the current User and + * a IdentifierChangeRequestEvent will be raised. This can then be used e.g. by the EmailPlugin to email + * that verification token to the Customer, which is then used to verify the change of email address. + */ + requestUpdateCustomerEmailAddress: RequestUpdateCustomerEmailAddressResult + /** + * Confirm the update of the emailAddress with the provided token, which has been generated by the + * `requestUpdateCustomerEmailAddress` mutation. + */ + updateCustomerEmailAddress: UpdateCustomerEmailAddressResult + /** Requests a password reset email to be sent */ + requestPasswordReset?: Maybe + /** Resets a Customer's password based on the provided token */ + resetPassword: ResetPasswordResult +} + +export type MutationAddItemToOrderArgs = { + productVariantId: Scalars['ID'] + quantity: Scalars['Int'] +} + +export type MutationRemoveOrderLineArgs = { + orderLineId: Scalars['ID'] +} + +export type MutationAdjustOrderLineArgs = { + orderLineId: Scalars['ID'] + quantity: Scalars['Int'] +} + +export type MutationApplyCouponCodeArgs = { + couponCode: Scalars['String'] +} + +export type MutationRemoveCouponCodeArgs = { + couponCode: Scalars['String'] +} + +export type MutationTransitionOrderToStateArgs = { + state: Scalars['String'] +} + +export type MutationSetOrderShippingAddressArgs = { + input: CreateAddressInput +} + +export type MutationSetOrderBillingAddressArgs = { + input: CreateAddressInput +} + +export type MutationSetOrderCustomFieldsArgs = { + input: UpdateOrderInput +} + +export type MutationSetOrderShippingMethodArgs = { + shippingMethodId: Scalars['ID'] +} + +export type MutationAddPaymentToOrderArgs = { + input: PaymentInput +} + +export type MutationSetCustomerForOrderArgs = { + input: CreateCustomerInput +} + +export type MutationLoginArgs = { + username: Scalars['String'] + password: Scalars['String'] + rememberMe?: Maybe +} + +export type MutationAuthenticateArgs = { + input: AuthenticationInput + rememberMe?: Maybe +} + +export type MutationRegisterCustomerAccountArgs = { + input: RegisterCustomerInput +} + +export type MutationRefreshCustomerVerificationArgs = { + emailAddress: Scalars['String'] +} + +export type MutationUpdateCustomerArgs = { + input: UpdateCustomerInput +} + +export type MutationCreateCustomerAddressArgs = { + input: CreateAddressInput +} + +export type MutationUpdateCustomerAddressArgs = { + input: UpdateAddressInput +} + +export type MutationDeleteCustomerAddressArgs = { + id: Scalars['ID'] +} + +export type MutationVerifyCustomerAccountArgs = { + token: Scalars['String'] + password?: Maybe +} + +export type MutationUpdateCustomerPasswordArgs = { + currentPassword: Scalars['String'] + newPassword: Scalars['String'] +} + +export type MutationRequestUpdateCustomerEmailAddressArgs = { + password: Scalars['String'] + newEmailAddress: Scalars['String'] +} + +export type MutationUpdateCustomerEmailAddressArgs = { + token: Scalars['String'] +} + +export type MutationRequestPasswordResetArgs = { + emailAddress: Scalars['String'] +} + +export type MutationResetPasswordArgs = { + token: Scalars['String'] + password: Scalars['String'] +} + +export type Address = Node & { + __typename?: 'Address' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + fullName?: Maybe + company?: Maybe + streetLine1: Scalars['String'] + streetLine2?: Maybe + city?: Maybe + province?: Maybe + postalCode?: Maybe + country: Country + phoneNumber?: Maybe + defaultShippingAddress?: Maybe + defaultBillingAddress?: Maybe + customFields?: Maybe +} + +export type Asset = Node & { + __typename?: 'Asset' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + name: Scalars['String'] + type: AssetType + fileSize: Scalars['Int'] + mimeType: Scalars['String'] + width: Scalars['Int'] + height: Scalars['Int'] + source: Scalars['String'] + preview: Scalars['String'] + focalPoint?: Maybe + customFields?: Maybe +} + +export type Coordinate = { + __typename?: 'Coordinate' + x: Scalars['Float'] + y: Scalars['Float'] +} + +export type AssetList = PaginatedList & { + __typename?: 'AssetList' + items: Array + totalItems: Scalars['Int'] +} + +export enum AssetType { + Image = 'IMAGE', + Video = 'VIDEO', + Binary = 'BINARY', +} + +export type CurrentUser = { + __typename?: 'CurrentUser' + id: Scalars['ID'] + identifier: Scalars['String'] + channels: Array +} + +export type CurrentUserChannel = { + __typename?: 'CurrentUserChannel' + id: Scalars['ID'] + token: Scalars['String'] + code: Scalars['String'] + permissions: Array +} + +export type Channel = Node & { + __typename?: 'Channel' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + code: Scalars['String'] + token: Scalars['String'] + defaultTaxZone?: Maybe + defaultShippingZone?: Maybe + defaultLanguageCode: LanguageCode + currencyCode: CurrencyCode + pricesIncludeTax: Scalars['Boolean'] + customFields?: Maybe +} + +export type Collection = Node & { + __typename?: 'Collection' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode?: Maybe + name: Scalars['String'] + slug: Scalars['String'] + breadcrumbs: Array + position: Scalars['Int'] + description: Scalars['String'] + featuredAsset?: Maybe + assets: Array + parent?: Maybe + children?: Maybe> + filters: Array + translations: Array + productVariants: ProductVariantList + customFields?: Maybe +} + +export type CollectionProductVariantsArgs = { + options?: Maybe +} + +export type CollectionBreadcrumb = { + __typename?: 'CollectionBreadcrumb' + id: Scalars['ID'] + name: Scalars['String'] + slug: Scalars['String'] +} + +export type CollectionTranslation = { + __typename?: 'CollectionTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] + slug: Scalars['String'] + description: Scalars['String'] +} + +export type CollectionList = PaginatedList & { + __typename?: 'CollectionList' + items: Array + totalItems: Scalars['Int'] +} + +export type ProductVariantList = PaginatedList & { + __typename?: 'ProductVariantList' + items: Array + totalItems: Scalars['Int'] +} + +export enum GlobalFlag { + True = 'TRUE', + False = 'FALSE', + Inherit = 'INHERIT', +} + +export enum AdjustmentType { + Promotion = 'PROMOTION', + DistributedOrderPromotion = 'DISTRIBUTED_ORDER_PROMOTION', +} + +export enum DeletionResult { + /** The entity was successfully deleted */ + Deleted = 'DELETED', + /** Deletion did not take place, reason given in message */ + NotDeleted = 'NOT_DELETED', +} + +/** + * @description + * Permissions for administrators and customers. Used to control access to + * GraphQL resolvers via the {@link Allow} decorator. + * + * @docsCategory common + */ +export enum Permission { + /** Authenticated means simply that the user is logged in */ + Authenticated = 'Authenticated', + /** SuperAdmin has unrestricted access to all operations */ + SuperAdmin = 'SuperAdmin', + /** Owner means the user owns this entity, e.g. a Customer's own Order */ + Owner = 'Owner', + /** Public means any unauthenticated user may perform the operation */ + Public = 'Public', + /** Grants permission to create Catalog */ + CreateCatalog = 'CreateCatalog', + /** Grants permission to read Catalog */ + ReadCatalog = 'ReadCatalog', + /** Grants permission to update Catalog */ + UpdateCatalog = 'UpdateCatalog', + /** Grants permission to delete Catalog */ + DeleteCatalog = 'DeleteCatalog', + /** Grants permission to create Customer */ + CreateCustomer = 'CreateCustomer', + /** Grants permission to read Customer */ + ReadCustomer = 'ReadCustomer', + /** Grants permission to update Customer */ + UpdateCustomer = 'UpdateCustomer', + /** Grants permission to delete Customer */ + DeleteCustomer = 'DeleteCustomer', + /** Grants permission to create Administrator */ + CreateAdministrator = 'CreateAdministrator', + /** Grants permission to read Administrator */ + ReadAdministrator = 'ReadAdministrator', + /** Grants permission to update Administrator */ + UpdateAdministrator = 'UpdateAdministrator', + /** Grants permission to delete Administrator */ + DeleteAdministrator = 'DeleteAdministrator', + /** Grants permission to create Order */ + CreateOrder = 'CreateOrder', + /** Grants permission to read Order */ + ReadOrder = 'ReadOrder', + /** Grants permission to update Order */ + UpdateOrder = 'UpdateOrder', + /** Grants permission to delete Order */ + DeleteOrder = 'DeleteOrder', + /** Grants permission to create Promotion */ + CreatePromotion = 'CreatePromotion', + /** Grants permission to read Promotion */ + ReadPromotion = 'ReadPromotion', + /** Grants permission to update Promotion */ + UpdatePromotion = 'UpdatePromotion', + /** Grants permission to delete Promotion */ + DeletePromotion = 'DeletePromotion', + /** Grants permission to create Settings */ + CreateSettings = 'CreateSettings', + /** Grants permission to read Settings */ + ReadSettings = 'ReadSettings', + /** Grants permission to update Settings */ + UpdateSettings = 'UpdateSettings', + /** Grants permission to delete Settings */ + DeleteSettings = 'DeleteSettings', +} + +export enum SortOrder { + Asc = 'ASC', + Desc = 'DESC', +} + +export enum ErrorCode { + UnknownError = 'UNKNOWN_ERROR', + NativeAuthStrategyError = 'NATIVE_AUTH_STRATEGY_ERROR', + InvalidCredentialsError = 'INVALID_CREDENTIALS_ERROR', + OrderStateTransitionError = 'ORDER_STATE_TRANSITION_ERROR', + EmailAddressConflictError = 'EMAIL_ADDRESS_CONFLICT_ERROR', + OrderLimitError = 'ORDER_LIMIT_ERROR', + NegativeQuantityError = 'NEGATIVE_QUANTITY_ERROR', + InsufficientStockError = 'INSUFFICIENT_STOCK_ERROR', + OrderModificationError = 'ORDER_MODIFICATION_ERROR', + IneligibleShippingMethodError = 'INELIGIBLE_SHIPPING_METHOD_ERROR', + OrderPaymentStateError = 'ORDER_PAYMENT_STATE_ERROR', + IneligiblePaymentMethodError = 'INELIGIBLE_PAYMENT_METHOD_ERROR', + PaymentFailedError = 'PAYMENT_FAILED_ERROR', + PaymentDeclinedError = 'PAYMENT_DECLINED_ERROR', + CouponCodeInvalidError = 'COUPON_CODE_INVALID_ERROR', + CouponCodeExpiredError = 'COUPON_CODE_EXPIRED_ERROR', + CouponCodeLimitError = 'COUPON_CODE_LIMIT_ERROR', + AlreadyLoggedInError = 'ALREADY_LOGGED_IN_ERROR', + MissingPasswordError = 'MISSING_PASSWORD_ERROR', + PasswordAlreadySetError = 'PASSWORD_ALREADY_SET_ERROR', + VerificationTokenInvalidError = 'VERIFICATION_TOKEN_INVALID_ERROR', + VerificationTokenExpiredError = 'VERIFICATION_TOKEN_EXPIRED_ERROR', + IdentifierChangeTokenInvalidError = 'IDENTIFIER_CHANGE_TOKEN_INVALID_ERROR', + IdentifierChangeTokenExpiredError = 'IDENTIFIER_CHANGE_TOKEN_EXPIRED_ERROR', + PasswordResetTokenInvalidError = 'PASSWORD_RESET_TOKEN_INVALID_ERROR', + PasswordResetTokenExpiredError = 'PASSWORD_RESET_TOKEN_EXPIRED_ERROR', + NotVerifiedError = 'NOT_VERIFIED_ERROR', + NoActiveOrderError = 'NO_ACTIVE_ORDER_ERROR', +} + +export enum LogicalOperator { + And = 'AND', + Or = 'OR', +} + +/** Retured when attempting an operation that relies on the NativeAuthStrategy, if that strategy is not configured. */ +export type NativeAuthStrategyError = ErrorResult & { + __typename?: 'NativeAuthStrategyError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** Returned if the user authentication credentials are not valid */ +export type InvalidCredentialsError = ErrorResult & { + __typename?: 'InvalidCredentialsError' + errorCode: ErrorCode + message: Scalars['String'] + authenticationError: Scalars['String'] +} + +/** Returned if there is an error in transitioning the Order state */ +export type OrderStateTransitionError = ErrorResult & { + __typename?: 'OrderStateTransitionError' + errorCode: ErrorCode + message: Scalars['String'] + transitionError: Scalars['String'] + fromState: Scalars['String'] + toState: Scalars['String'] +} + +/** Retured when attemting to create a Customer with an email address already registered to an existing User. */ +export type EmailAddressConflictError = ErrorResult & { + __typename?: 'EmailAddressConflictError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** Retured when the maximum order size limit has been reached. */ +export type OrderLimitError = ErrorResult & { + __typename?: 'OrderLimitError' + errorCode: ErrorCode + message: Scalars['String'] + maxItems: Scalars['Int'] +} + +/** Retured when attemting to set a negative OrderLine quantity. */ +export type NegativeQuantityError = ErrorResult & { + __typename?: 'NegativeQuantityError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** Returned when attempting to add more items to the Order than are available */ +export type InsufficientStockError = ErrorResult & { + __typename?: 'InsufficientStockError' + errorCode: ErrorCode + message: Scalars['String'] + quantityAvailable: Scalars['Int'] + order: Order +} + +export type PaginatedList = { + items: Array + totalItems: Scalars['Int'] +} + +export type Node = { + id: Scalars['ID'] +} + +export type ErrorResult = { + errorCode: ErrorCode + message: Scalars['String'] +} + +export type Adjustment = { + __typename?: 'Adjustment' + adjustmentSource: Scalars['String'] + type: AdjustmentType + description: Scalars['String'] + amount: Scalars['Int'] +} + +export type TaxLine = { + __typename?: 'TaxLine' + description: Scalars['String'] + taxRate: Scalars['Float'] +} + +export type ConfigArg = { + __typename?: 'ConfigArg' + name: Scalars['String'] + value: Scalars['String'] +} + +export type ConfigArgDefinition = { + __typename?: 'ConfigArgDefinition' + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + required: Scalars['Boolean'] + defaultValue?: Maybe + label?: Maybe + description?: Maybe + ui?: Maybe +} + +export type ConfigurableOperation = { + __typename?: 'ConfigurableOperation' + code: Scalars['String'] + args: Array +} + +export type ConfigurableOperationDefinition = { + __typename?: 'ConfigurableOperationDefinition' + code: Scalars['String'] + args: Array + description: Scalars['String'] +} + +export type DeletionResponse = { + __typename?: 'DeletionResponse' + result: DeletionResult + message?: Maybe +} + +export type ConfigArgInput = { + name: Scalars['String'] + /** A JSON stringified representation of the actual value */ + value: Scalars['String'] +} + +export type ConfigurableOperationInput = { + code: Scalars['String'] + arguments: Array +} + +export type StringOperators = { + eq?: Maybe + notEq?: Maybe + contains?: Maybe + notContains?: Maybe + in?: Maybe> + notIn?: Maybe> + regex?: Maybe +} + +export type BooleanOperators = { + eq?: Maybe +} + +export type NumberRange = { + start: Scalars['Float'] + end: Scalars['Float'] +} + +export type NumberOperators = { + eq?: Maybe + lt?: Maybe + lte?: Maybe + gt?: Maybe + gte?: Maybe + between?: Maybe +} + +export type DateRange = { + start: Scalars['DateTime'] + end: Scalars['DateTime'] +} + +export type DateOperators = { + eq?: Maybe + before?: Maybe + after?: Maybe + between?: Maybe +} + +export type SearchInput = { + term?: Maybe + facetValueIds?: Maybe> + facetValueOperator?: Maybe + collectionId?: Maybe + collectionSlug?: Maybe + groupByProduct?: Maybe + take?: Maybe + skip?: Maybe + sort?: Maybe +} + +export type SearchResultSortParameter = { + name?: Maybe + price?: Maybe +} + +export type CreateCustomerInput = { + title?: Maybe + firstName: Scalars['String'] + lastName: Scalars['String'] + phoneNumber?: Maybe + emailAddress: Scalars['String'] + customFields?: Maybe +} + +export type CreateAddressInput = { + fullName?: Maybe + company?: Maybe + streetLine1: Scalars['String'] + streetLine2?: Maybe + city?: Maybe + province?: Maybe + postalCode?: Maybe + countryCode: Scalars['String'] + phoneNumber?: Maybe + defaultShippingAddress?: Maybe + defaultBillingAddress?: Maybe + customFields?: Maybe +} + +export type UpdateAddressInput = { + id: Scalars['ID'] + fullName?: Maybe + company?: Maybe + streetLine1?: Maybe + streetLine2?: Maybe + city?: Maybe + province?: Maybe + postalCode?: Maybe + countryCode?: Maybe + phoneNumber?: Maybe + defaultShippingAddress?: Maybe + defaultBillingAddress?: Maybe + customFields?: Maybe +} + +/** Indicates that an operation succeeded, where we do not want to return any more specific information. */ +export type Success = { + __typename?: 'Success' + success: Scalars['Boolean'] +} + +export type ShippingMethodQuote = { + __typename?: 'ShippingMethodQuote' + id: Scalars['ID'] + price: Scalars['Int'] + priceWithTax: Scalars['Int'] + name: Scalars['String'] + description: Scalars['String'] + /** Any optional metadata returned by the ShippingCalculator in the ShippingCalculationResult */ + metadata?: Maybe +} + +export type PaymentMethodQuote = { + __typename?: 'PaymentMethodQuote' + id: Scalars['ID'] + code: Scalars['String'] + isEligible: Scalars['Boolean'] + eligibilityMessage?: Maybe +} + +export type Country = Node & { + __typename?: 'Country' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + code: Scalars['String'] + name: Scalars['String'] + enabled: Scalars['Boolean'] + translations: Array +} + +export type CountryTranslation = { + __typename?: 'CountryTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] +} + +export type CountryList = PaginatedList & { + __typename?: 'CountryList' + items: Array + totalItems: Scalars['Int'] +} + +/** + * @description + * ISO 4217 currency code + * + * @docsCategory common + */ +export enum CurrencyCode { + /** United Arab Emirates dirham */ + Aed = 'AED', + /** Afghan afghani */ + Afn = 'AFN', + /** Albanian lek */ + All = 'ALL', + /** Armenian dram */ + Amd = 'AMD', + /** Netherlands Antillean guilder */ + Ang = 'ANG', + /** Angolan kwanza */ + Aoa = 'AOA', + /** Argentine peso */ + Ars = 'ARS', + /** Australian dollar */ + Aud = 'AUD', + /** Aruban florin */ + Awg = 'AWG', + /** Azerbaijani manat */ + Azn = 'AZN', + /** Bosnia and Herzegovina convertible mark */ + Bam = 'BAM', + /** Barbados dollar */ + Bbd = 'BBD', + /** Bangladeshi taka */ + Bdt = 'BDT', + /** Bulgarian lev */ + Bgn = 'BGN', + /** Bahraini dinar */ + Bhd = 'BHD', + /** Burundian franc */ + Bif = 'BIF', + /** Bermudian dollar */ + Bmd = 'BMD', + /** Brunei dollar */ + Bnd = 'BND', + /** Boliviano */ + Bob = 'BOB', + /** Brazilian real */ + Brl = 'BRL', + /** Bahamian dollar */ + Bsd = 'BSD', + /** Bhutanese ngultrum */ + Btn = 'BTN', + /** Botswana pula */ + Bwp = 'BWP', + /** Belarusian ruble */ + Byn = 'BYN', + /** Belize dollar */ + Bzd = 'BZD', + /** Canadian dollar */ + Cad = 'CAD', + /** Congolese franc */ + Cdf = 'CDF', + /** Swiss franc */ + Chf = 'CHF', + /** Chilean peso */ + Clp = 'CLP', + /** Renminbi (Chinese) yuan */ + Cny = 'CNY', + /** Colombian peso */ + Cop = 'COP', + /** Costa Rican colon */ + Crc = 'CRC', + /** Cuban convertible peso */ + Cuc = 'CUC', + /** Cuban peso */ + Cup = 'CUP', + /** Cape Verde escudo */ + Cve = 'CVE', + /** Czech koruna */ + Czk = 'CZK', + /** Djiboutian franc */ + Djf = 'DJF', + /** Danish krone */ + Dkk = 'DKK', + /** Dominican peso */ + Dop = 'DOP', + /** Algerian dinar */ + Dzd = 'DZD', + /** Egyptian pound */ + Egp = 'EGP', + /** Eritrean nakfa */ + Ern = 'ERN', + /** Ethiopian birr */ + Etb = 'ETB', + /** Euro */ + Eur = 'EUR', + /** Fiji dollar */ + Fjd = 'FJD', + /** Falkland Islands pound */ + Fkp = 'FKP', + /** Pound sterling */ + Gbp = 'GBP', + /** Georgian lari */ + Gel = 'GEL', + /** Ghanaian cedi */ + Ghs = 'GHS', + /** Gibraltar pound */ + Gip = 'GIP', + /** Gambian dalasi */ + Gmd = 'GMD', + /** Guinean franc */ + Gnf = 'GNF', + /** Guatemalan quetzal */ + Gtq = 'GTQ', + /** Guyanese dollar */ + Gyd = 'GYD', + /** Hong Kong dollar */ + Hkd = 'HKD', + /** Honduran lempira */ + Hnl = 'HNL', + /** Croatian kuna */ + Hrk = 'HRK', + /** Haitian gourde */ + Htg = 'HTG', + /** Hungarian forint */ + Huf = 'HUF', + /** Indonesian rupiah */ + Idr = 'IDR', + /** Israeli new shekel */ + Ils = 'ILS', + /** Indian rupee */ + Inr = 'INR', + /** Iraqi dinar */ + Iqd = 'IQD', + /** Iranian rial */ + Irr = 'IRR', + /** Icelandic króna */ + Isk = 'ISK', + /** Jamaican dollar */ + Jmd = 'JMD', + /** Jordanian dinar */ + Jod = 'JOD', + /** Japanese yen */ + Jpy = 'JPY', + /** Kenyan shilling */ + Kes = 'KES', + /** Kyrgyzstani som */ + Kgs = 'KGS', + /** Cambodian riel */ + Khr = 'KHR', + /** Comoro franc */ + Kmf = 'KMF', + /** North Korean won */ + Kpw = 'KPW', + /** South Korean won */ + Krw = 'KRW', + /** Kuwaiti dinar */ + Kwd = 'KWD', + /** Cayman Islands dollar */ + Kyd = 'KYD', + /** Kazakhstani tenge */ + Kzt = 'KZT', + /** Lao kip */ + Lak = 'LAK', + /** Lebanese pound */ + Lbp = 'LBP', + /** Sri Lankan rupee */ + Lkr = 'LKR', + /** Liberian dollar */ + Lrd = 'LRD', + /** Lesotho loti */ + Lsl = 'LSL', + /** Libyan dinar */ + Lyd = 'LYD', + /** Moroccan dirham */ + Mad = 'MAD', + /** Moldovan leu */ + Mdl = 'MDL', + /** Malagasy ariary */ + Mga = 'MGA', + /** Macedonian denar */ + Mkd = 'MKD', + /** Myanmar kyat */ + Mmk = 'MMK', + /** Mongolian tögrög */ + Mnt = 'MNT', + /** Macanese pataca */ + Mop = 'MOP', + /** Mauritanian ouguiya */ + Mru = 'MRU', + /** Mauritian rupee */ + Mur = 'MUR', + /** Maldivian rufiyaa */ + Mvr = 'MVR', + /** Malawian kwacha */ + Mwk = 'MWK', + /** Mexican peso */ + Mxn = 'MXN', + /** Malaysian ringgit */ + Myr = 'MYR', + /** Mozambican metical */ + Mzn = 'MZN', + /** Namibian dollar */ + Nad = 'NAD', + /** Nigerian naira */ + Ngn = 'NGN', + /** Nicaraguan córdoba */ + Nio = 'NIO', + /** Norwegian krone */ + Nok = 'NOK', + /** Nepalese rupee */ + Npr = 'NPR', + /** New Zealand dollar */ + Nzd = 'NZD', + /** Omani rial */ + Omr = 'OMR', + /** Panamanian balboa */ + Pab = 'PAB', + /** Peruvian sol */ + Pen = 'PEN', + /** Papua New Guinean kina */ + Pgk = 'PGK', + /** Philippine peso */ + Php = 'PHP', + /** Pakistani rupee */ + Pkr = 'PKR', + /** Polish złoty */ + Pln = 'PLN', + /** Paraguayan guaraní */ + Pyg = 'PYG', + /** Qatari riyal */ + Qar = 'QAR', + /** Romanian leu */ + Ron = 'RON', + /** Serbian dinar */ + Rsd = 'RSD', + /** Russian ruble */ + Rub = 'RUB', + /** Rwandan franc */ + Rwf = 'RWF', + /** Saudi riyal */ + Sar = 'SAR', + /** Solomon Islands dollar */ + Sbd = 'SBD', + /** Seychelles rupee */ + Scr = 'SCR', + /** Sudanese pound */ + Sdg = 'SDG', + /** Swedish krona/kronor */ + Sek = 'SEK', + /** Singapore dollar */ + Sgd = 'SGD', + /** Saint Helena pound */ + Shp = 'SHP', + /** Sierra Leonean leone */ + Sll = 'SLL', + /** Somali shilling */ + Sos = 'SOS', + /** Surinamese dollar */ + Srd = 'SRD', + /** South Sudanese pound */ + Ssp = 'SSP', + /** São Tomé and Príncipe dobra */ + Stn = 'STN', + /** Salvadoran colón */ + Svc = 'SVC', + /** Syrian pound */ + Syp = 'SYP', + /** Swazi lilangeni */ + Szl = 'SZL', + /** Thai baht */ + Thb = 'THB', + /** Tajikistani somoni */ + Tjs = 'TJS', + /** Turkmenistan manat */ + Tmt = 'TMT', + /** Tunisian dinar */ + Tnd = 'TND', + /** Tongan paʻanga */ + Top = 'TOP', + /** Turkish lira */ + Try = 'TRY', + /** Trinidad and Tobago dollar */ + Ttd = 'TTD', + /** New Taiwan dollar */ + Twd = 'TWD', + /** Tanzanian shilling */ + Tzs = 'TZS', + /** Ukrainian hryvnia */ + Uah = 'UAH', + /** Ugandan shilling */ + Ugx = 'UGX', + /** United States dollar */ + Usd = 'USD', + /** Uruguayan peso */ + Uyu = 'UYU', + /** Uzbekistan som */ + Uzs = 'UZS', + /** Venezuelan bolívar soberano */ + Ves = 'VES', + /** Vietnamese đồng */ + Vnd = 'VND', + /** Vanuatu vatu */ + Vuv = 'VUV', + /** Samoan tala */ + Wst = 'WST', + /** CFA franc BEAC */ + Xaf = 'XAF', + /** East Caribbean dollar */ + Xcd = 'XCD', + /** CFA franc BCEAO */ + Xof = 'XOF', + /** CFP franc (franc Pacifique) */ + Xpf = 'XPF', + /** Yemeni rial */ + Yer = 'YER', + /** South African rand */ + Zar = 'ZAR', + /** Zambian kwacha */ + Zmw = 'ZMW', + /** Zimbabwean dollar */ + Zwl = 'ZWL', +} + +export type CustomField = { + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + label?: Maybe> + description?: Maybe> + readonly?: Maybe + internal?: Maybe +} + +export type StringCustomFieldConfig = CustomField & { + __typename?: 'StringCustomFieldConfig' + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + length?: Maybe + label?: Maybe> + description?: Maybe> + readonly?: Maybe + internal?: Maybe + pattern?: Maybe + options?: Maybe> +} + +export type StringFieldOption = { + __typename?: 'StringFieldOption' + value: Scalars['String'] + label?: Maybe> +} + +export type LocaleStringCustomFieldConfig = CustomField & { + __typename?: 'LocaleStringCustomFieldConfig' + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + length?: Maybe + label?: Maybe> + description?: Maybe> + readonly?: Maybe + internal?: Maybe + pattern?: Maybe +} + +export type IntCustomFieldConfig = CustomField & { + __typename?: 'IntCustomFieldConfig' + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + label?: Maybe> + description?: Maybe> + readonly?: Maybe + internal?: Maybe + min?: Maybe + max?: Maybe + step?: Maybe +} + +export type FloatCustomFieldConfig = CustomField & { + __typename?: 'FloatCustomFieldConfig' + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + label?: Maybe> + description?: Maybe> + readonly?: Maybe + internal?: Maybe + min?: Maybe + max?: Maybe + step?: Maybe +} + +export type BooleanCustomFieldConfig = CustomField & { + __typename?: 'BooleanCustomFieldConfig' + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + label?: Maybe> + description?: Maybe> + readonly?: Maybe + internal?: Maybe +} + +/** + * Expects the same validation formats as the `` HTML element. + * See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local#Additional_attributes + */ +export type DateTimeCustomFieldConfig = CustomField & { + __typename?: 'DateTimeCustomFieldConfig' + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + label?: Maybe> + description?: Maybe> + readonly?: Maybe + internal?: Maybe + min?: Maybe + max?: Maybe + step?: Maybe +} + +export type RelationCustomFieldConfig = CustomField & { + __typename?: 'RelationCustomFieldConfig' + name: Scalars['String'] + type: Scalars['String'] + list: Scalars['Boolean'] + label?: Maybe> + description?: Maybe> + readonly?: Maybe + internal?: Maybe + entity: Scalars['String'] + scalarFields: Array +} + +export type LocalizedString = { + __typename?: 'LocalizedString' + languageCode: LanguageCode + value: Scalars['String'] +} + +export type CustomFieldConfig = + | StringCustomFieldConfig + | LocaleStringCustomFieldConfig + | IntCustomFieldConfig + | FloatCustomFieldConfig + | BooleanCustomFieldConfig + | DateTimeCustomFieldConfig + | RelationCustomFieldConfig + +export type CustomerGroup = Node & { + __typename?: 'CustomerGroup' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + name: Scalars['String'] + customers: CustomerList +} + +export type CustomerGroupCustomersArgs = { + options?: Maybe +} + +export type Customer = Node & { + __typename?: 'Customer' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + title?: Maybe + firstName: Scalars['String'] + lastName: Scalars['String'] + phoneNumber?: Maybe + emailAddress: Scalars['String'] + addresses?: Maybe> + orders: OrderList + user?: Maybe + customFields?: Maybe +} + +export type CustomerOrdersArgs = { + options?: Maybe +} + +export type CustomerList = PaginatedList & { + __typename?: 'CustomerList' + items: Array + totalItems: Scalars['Int'] +} + +export type FacetValue = Node & { + __typename?: 'FacetValue' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + facet: Facet + name: Scalars['String'] + code: Scalars['String'] + translations: Array + customFields?: Maybe +} + +export type FacetValueTranslation = { + __typename?: 'FacetValueTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] +} + +export type Facet = Node & { + __typename?: 'Facet' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] + code: Scalars['String'] + values: Array + translations: Array + customFields?: Maybe +} + +export type FacetTranslation = { + __typename?: 'FacetTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] +} + +export type FacetList = PaginatedList & { + __typename?: 'FacetList' + items: Array + totalItems: Scalars['Int'] +} + +export type HistoryEntry = Node & { + __typename?: 'HistoryEntry' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + type: HistoryEntryType + data: Scalars['JSON'] +} + +export enum HistoryEntryType { + CustomerRegistered = 'CUSTOMER_REGISTERED', + CustomerVerified = 'CUSTOMER_VERIFIED', + CustomerDetailUpdated = 'CUSTOMER_DETAIL_UPDATED', + CustomerAddedToGroup = 'CUSTOMER_ADDED_TO_GROUP', + CustomerRemovedFromGroup = 'CUSTOMER_REMOVED_FROM_GROUP', + CustomerAddressCreated = 'CUSTOMER_ADDRESS_CREATED', + CustomerAddressUpdated = 'CUSTOMER_ADDRESS_UPDATED', + CustomerAddressDeleted = 'CUSTOMER_ADDRESS_DELETED', + CustomerPasswordUpdated = 'CUSTOMER_PASSWORD_UPDATED', + CustomerPasswordResetRequested = 'CUSTOMER_PASSWORD_RESET_REQUESTED', + CustomerPasswordResetVerified = 'CUSTOMER_PASSWORD_RESET_VERIFIED', + CustomerEmailUpdateRequested = 'CUSTOMER_EMAIL_UPDATE_REQUESTED', + CustomerEmailUpdateVerified = 'CUSTOMER_EMAIL_UPDATE_VERIFIED', + CustomerNote = 'CUSTOMER_NOTE', + OrderStateTransition = 'ORDER_STATE_TRANSITION', + OrderPaymentTransition = 'ORDER_PAYMENT_TRANSITION', + OrderFulfillment = 'ORDER_FULFILLMENT', + OrderCancellation = 'ORDER_CANCELLATION', + OrderRefundTransition = 'ORDER_REFUND_TRANSITION', + OrderFulfillmentTransition = 'ORDER_FULFILLMENT_TRANSITION', + OrderNote = 'ORDER_NOTE', + OrderCouponApplied = 'ORDER_COUPON_APPLIED', + OrderCouponRemoved = 'ORDER_COUPON_REMOVED', + OrderModified = 'ORDER_MODIFIED', +} + +export type HistoryEntryList = PaginatedList & { + __typename?: 'HistoryEntryList' + items: Array + totalItems: Scalars['Int'] +} + +/** + * @description + * Languages in the form of a ISO 639-1 language code with optional + * region or script modifier (e.g. de_AT). The selection available is based + * on the [Unicode CLDR summary list](https://unicode-org.github.io/cldr-staging/charts/37/summary/root.html) + * and includes the major spoken languages of the world and any widely-used variants. + * + * @docsCategory common + */ +export enum LanguageCode { + /** Afrikaans */ + Af = 'af', + /** Akan */ + Ak = 'ak', + /** Albanian */ + Sq = 'sq', + /** Amharic */ + Am = 'am', + /** Arabic */ + Ar = 'ar', + /** Armenian */ + Hy = 'hy', + /** Assamese */ + As = 'as', + /** Azerbaijani */ + Az = 'az', + /** Bambara */ + Bm = 'bm', + /** Bangla */ + Bn = 'bn', + /** Basque */ + Eu = 'eu', + /** Belarusian */ + Be = 'be', + /** Bosnian */ + Bs = 'bs', + /** Breton */ + Br = 'br', + /** Bulgarian */ + Bg = 'bg', + /** Burmese */ + My = 'my', + /** Catalan */ + Ca = 'ca', + /** Chechen */ + Ce = 'ce', + /** Chinese */ + Zh = 'zh', + /** Simplified Chinese */ + ZhHans = 'zh_Hans', + /** Traditional Chinese */ + ZhHant = 'zh_Hant', + /** Church Slavic */ + Cu = 'cu', + /** Cornish */ + Kw = 'kw', + /** Corsican */ + Co = 'co', + /** Croatian */ + Hr = 'hr', + /** Czech */ + Cs = 'cs', + /** Danish */ + Da = 'da', + /** Dutch */ + Nl = 'nl', + /** Flemish */ + NlBe = 'nl_BE', + /** Dzongkha */ + Dz = 'dz', + /** English */ + En = 'en', + /** Australian English */ + EnAu = 'en_AU', + /** Canadian English */ + EnCa = 'en_CA', + /** British English */ + EnGb = 'en_GB', + /** American English */ + EnUs = 'en_US', + /** Esperanto */ + Eo = 'eo', + /** Estonian */ + Et = 'et', + /** Ewe */ + Ee = 'ee', + /** Faroese */ + Fo = 'fo', + /** Finnish */ + Fi = 'fi', + /** French */ + Fr = 'fr', + /** Canadian French */ + FrCa = 'fr_CA', + /** Swiss French */ + FrCh = 'fr_CH', + /** Fulah */ + Ff = 'ff', + /** Galician */ + Gl = 'gl', + /** Ganda */ + Lg = 'lg', + /** Georgian */ + Ka = 'ka', + /** German */ + De = 'de', + /** Austrian German */ + DeAt = 'de_AT', + /** Swiss High German */ + DeCh = 'de_CH', + /** Greek */ + El = 'el', + /** Gujarati */ + Gu = 'gu', + /** Haitian Creole */ + Ht = 'ht', + /** Hausa */ + Ha = 'ha', + /** Hebrew */ + He = 'he', + /** Hindi */ + Hi = 'hi', + /** Hungarian */ + Hu = 'hu', + /** Icelandic */ + Is = 'is', + /** Igbo */ + Ig = 'ig', + /** Indonesian */ + Id = 'id', + /** Interlingua */ + Ia = 'ia', + /** Irish */ + Ga = 'ga', + /** Italian */ + It = 'it', + /** Japanese */ + Ja = 'ja', + /** Javanese */ + Jv = 'jv', + /** Kalaallisut */ + Kl = 'kl', + /** Kannada */ + Kn = 'kn', + /** Kashmiri */ + Ks = 'ks', + /** Kazakh */ + Kk = 'kk', + /** Khmer */ + Km = 'km', + /** Kikuyu */ + Ki = 'ki', + /** Kinyarwanda */ + Rw = 'rw', + /** Korean */ + Ko = 'ko', + /** Kurdish */ + Ku = 'ku', + /** Kyrgyz */ + Ky = 'ky', + /** Lao */ + Lo = 'lo', + /** Latin */ + La = 'la', + /** Latvian */ + Lv = 'lv', + /** Lingala */ + Ln = 'ln', + /** Lithuanian */ + Lt = 'lt', + /** Luba-Katanga */ + Lu = 'lu', + /** Luxembourgish */ + Lb = 'lb', + /** Macedonian */ + Mk = 'mk', + /** Malagasy */ + Mg = 'mg', + /** Malay */ + Ms = 'ms', + /** Malayalam */ + Ml = 'ml', + /** Maltese */ + Mt = 'mt', + /** Manx */ + Gv = 'gv', + /** Maori */ + Mi = 'mi', + /** Marathi */ + Mr = 'mr', + /** Mongolian */ + Mn = 'mn', + /** Nepali */ + Ne = 'ne', + /** North Ndebele */ + Nd = 'nd', + /** Northern Sami */ + Se = 'se', + /** Norwegian Bokmål */ + Nb = 'nb', + /** Norwegian Nynorsk */ + Nn = 'nn', + /** Nyanja */ + Ny = 'ny', + /** Odia */ + Or = 'or', + /** Oromo */ + Om = 'om', + /** Ossetic */ + Os = 'os', + /** Pashto */ + Ps = 'ps', + /** Persian */ + Fa = 'fa', + /** Dari */ + FaAf = 'fa_AF', + /** Polish */ + Pl = 'pl', + /** Portuguese */ + Pt = 'pt', + /** Brazilian Portuguese */ + PtBr = 'pt_BR', + /** European Portuguese */ + PtPt = 'pt_PT', + /** Punjabi */ + Pa = 'pa', + /** Quechua */ + Qu = 'qu', + /** Romanian */ + Ro = 'ro', + /** Moldavian */ + RoMd = 'ro_MD', + /** Romansh */ + Rm = 'rm', + /** Rundi */ + Rn = 'rn', + /** Russian */ + Ru = 'ru', + /** Samoan */ + Sm = 'sm', + /** Sango */ + Sg = 'sg', + /** Sanskrit */ + Sa = 'sa', + /** Scottish Gaelic */ + Gd = 'gd', + /** Serbian */ + Sr = 'sr', + /** Shona */ + Sn = 'sn', + /** Sichuan Yi */ + Ii = 'ii', + /** Sindhi */ + Sd = 'sd', + /** Sinhala */ + Si = 'si', + /** Slovak */ + Sk = 'sk', + /** Slovenian */ + Sl = 'sl', + /** Somali */ + So = 'so', + /** Southern Sotho */ + St = 'st', + /** Spanish */ + Es = 'es', + /** European Spanish */ + EsEs = 'es_ES', + /** Mexican Spanish */ + EsMx = 'es_MX', + /** Sundanese */ + Su = 'su', + /** Swahili */ + Sw = 'sw', + /** Congo Swahili */ + SwCd = 'sw_CD', + /** Swedish */ + Sv = 'sv', + /** Tajik */ + Tg = 'tg', + /** Tamil */ + Ta = 'ta', + /** Tatar */ + Tt = 'tt', + /** Telugu */ + Te = 'te', + /** Thai */ + Th = 'th', + /** Tibetan */ + Bo = 'bo', + /** Tigrinya */ + Ti = 'ti', + /** Tongan */ + To = 'to', + /** Turkish */ + Tr = 'tr', + /** Turkmen */ + Tk = 'tk', + /** Ukrainian */ + Uk = 'uk', + /** Urdu */ + Ur = 'ur', + /** Uyghur */ + Ug = 'ug', + /** Uzbek */ + Uz = 'uz', + /** Vietnamese */ + Vi = 'vi', + /** Volapük */ + Vo = 'vo', + /** Welsh */ + Cy = 'cy', + /** Western Frisian */ + Fy = 'fy', + /** Wolof */ + Wo = 'wo', + /** Xhosa */ + Xh = 'xh', + /** Yiddish */ + Yi = 'yi', + /** Yoruba */ + Yo = 'yo', + /** Zulu */ + Zu = 'zu', +} + +export type Order = Node & { + __typename?: 'Order' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + /** + * The date & time that the Order was placed, i.e. the Customer + * completed the checkout and the Order is no longer "active" + */ + orderPlacedAt?: Maybe + /** A unique code for the Order */ + code: Scalars['String'] + state: Scalars['String'] + /** An order is active as long as the payment process has not been completed */ + active: Scalars['Boolean'] + customer?: Maybe + shippingAddress?: Maybe + billingAddress?: Maybe + lines: Array + /** + * Surcharges are arbitrary modifications to the Order total which are neither + * ProductVariants nor discounts resulting from applied Promotions. For example, + * one-off discounts based on customer interaction, or surcharges based on payment + * methods. + */ + surcharges: Array + /** + * Order-level adjustments to the order total, such as discounts from promotions + * @deprecated Use `discounts` instead + */ + adjustments: Array + discounts: Array + /** An array of all coupon codes applied to the Order */ + couponCodes: Array + /** Promotions applied to the order. Only gets populated after the payment process has completed. */ + promotions: Array + payments?: Maybe> + fulfillments?: Maybe> + totalQuantity: Scalars['Int'] + /** + * The subTotal is the total of all OrderLines in the Order. This figure also includes any Order-level + * discounts which have been prorated (proportionally distributed) amongst the OrderItems. + * To get a total of all OrderLines which does not account for prorated discounts, use the + * sum of `OrderLine.discountedLinePrice` values. + */ + subTotal: Scalars['Int'] + /** Same as subTotal, but inclusive of tax */ + subTotalWithTax: Scalars['Int'] + currencyCode: CurrencyCode + shippingLines: Array + shipping: Scalars['Int'] + shippingWithTax: Scalars['Int'] + /** Equal to subTotal plus shipping */ + total: Scalars['Int'] + /** The final payable amount. Equal to subTotalWithTax plus shippingWithTax */ + totalWithTax: Scalars['Int'] + /** A summary of the taxes being applied to this Order */ + taxSummary: Array + history: HistoryEntryList + customFields?: Maybe +} + +export type OrderHistoryArgs = { + options?: Maybe +} + +/** + * A summary of the taxes being applied to this order, grouped + * by taxRate. + */ +export type OrderTaxSummary = { + __typename?: 'OrderTaxSummary' + /** A description of this tax */ + description: Scalars['String'] + /** The taxRate as a percentage */ + taxRate: Scalars['Float'] + /** The total net price or OrderItems to which this taxRate applies */ + taxBase: Scalars['Int'] + /** The total tax being applied to the Order at this taxRate */ + taxTotal: Scalars['Int'] +} + +export type OrderAddress = { + __typename?: 'OrderAddress' + fullName?: Maybe + company?: Maybe + streetLine1?: Maybe + streetLine2?: Maybe + city?: Maybe + province?: Maybe + postalCode?: Maybe + country?: Maybe + countryCode?: Maybe + phoneNumber?: Maybe + customFields?: Maybe +} + +export type OrderList = PaginatedList & { + __typename?: 'OrderList' + items: Array + totalItems: Scalars['Int'] +} + +export type ShippingLine = { + __typename?: 'ShippingLine' + shippingMethod: ShippingMethod + price: Scalars['Int'] + priceWithTax: Scalars['Int'] + discountedPrice: Scalars['Int'] + discountedPriceWithTax: Scalars['Int'] + discounts: Array +} + +export type OrderItem = Node & { + __typename?: 'OrderItem' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + cancelled: Scalars['Boolean'] + /** The price of a single unit, excluding tax and discounts */ + unitPrice: Scalars['Int'] + /** The price of a single unit, including tax but excluding discounts */ + unitPriceWithTax: Scalars['Int'] + /** + * The price of a single unit including discounts, excluding tax. + * + * If Order-level discounts have been applied, this will not be the + * actual taxable unit price (see `proratedUnitPrice`), but is generally the + * correct price to display to customers to avoid confusion + * about the internal handling of distributed Order-level discounts. + */ + discountedUnitPrice: Scalars['Int'] + /** The price of a single unit including discounts and tax */ + discountedUnitPriceWithTax: Scalars['Int'] + /** + * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed) + * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax + * and refund calculations. + */ + proratedUnitPrice: Scalars['Int'] + /** The proratedUnitPrice including tax */ + proratedUnitPriceWithTax: Scalars['Int'] + unitTax: Scalars['Int'] + /** @deprecated `unitPrice` is now always without tax */ + unitPriceIncludesTax: Scalars['Boolean'] + taxRate: Scalars['Float'] + adjustments: Array + taxLines: Array + fulfillment?: Maybe + refundId?: Maybe +} + +export type OrderLine = Node & { + __typename?: 'OrderLine' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + productVariant: ProductVariant + featuredAsset?: Maybe + /** The price of a single unit, excluding tax and discounts */ + unitPrice: Scalars['Int'] + /** The price of a single unit, including tax but excluding discounts */ + unitPriceWithTax: Scalars['Int'] + /** Non-zero if the unitPrice has changed since it was initially added to Order */ + unitPriceChangeSinceAdded: Scalars['Int'] + /** Non-zero if the unitPriceWithTax has changed since it was initially added to Order */ + unitPriceWithTaxChangeSinceAdded: Scalars['Int'] + /** + * The price of a single unit including discounts, excluding tax. + * + * If Order-level discounts have been applied, this will not be the + * actual taxable unit price (see `proratedUnitPrice`), but is generally the + * correct price to display to customers to avoid confusion + * about the internal handling of distributed Order-level discounts. + */ + discountedUnitPrice: Scalars['Int'] + /** The price of a single unit including discounts and tax */ + discountedUnitPriceWithTax: Scalars['Int'] + /** + * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed) + * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax + * and refund calculations. + */ + proratedUnitPrice: Scalars['Int'] + /** The proratedUnitPrice including tax */ + proratedUnitPriceWithTax: Scalars['Int'] + quantity: Scalars['Int'] + items: Array + /** @deprecated Use `linePriceWithTax` instead */ + totalPrice: Scalars['Int'] + taxRate: Scalars['Float'] + /** The total price of the line excluding tax and discounts. */ + linePrice: Scalars['Int'] + /** The total price of the line including tax bit excluding discounts. */ + linePriceWithTax: Scalars['Int'] + /** The price of the line including discounts, excluding tax */ + discountedLinePrice: Scalars['Int'] + /** The price of the line including discounts and tax */ + discountedLinePriceWithTax: Scalars['Int'] + /** + * The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed) + * Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax + * and refund calculations. + */ + proratedLinePrice: Scalars['Int'] + /** The proratedLinePrice including tax */ + proratedLinePriceWithTax: Scalars['Int'] + /** The total tax on this line */ + lineTax: Scalars['Int'] + /** @deprecated Use `discounts` instead */ + adjustments: Array + discounts: Array + taxLines: Array + order: Order + customFields?: Maybe +} + +export type Payment = Node & { + __typename?: 'Payment' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + method: Scalars['String'] + amount: Scalars['Int'] + state: Scalars['String'] + transactionId?: Maybe + errorMessage?: Maybe + refunds: Array + metadata?: Maybe +} + +export type Refund = Node & { + __typename?: 'Refund' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + items: Scalars['Int'] + shipping: Scalars['Int'] + adjustment: Scalars['Int'] + total: Scalars['Int'] + method?: Maybe + state: Scalars['String'] + transactionId?: Maybe + reason?: Maybe + orderItems: Array + paymentId: Scalars['ID'] + metadata?: Maybe +} + +export type Fulfillment = Node & { + __typename?: 'Fulfillment' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + orderItems: Array + state: Scalars['String'] + method: Scalars['String'] + trackingCode?: Maybe + customFields?: Maybe +} + +export type Surcharge = Node & { + __typename?: 'Surcharge' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + description: Scalars['String'] + sku?: Maybe + taxLines: Array + price: Scalars['Int'] + priceWithTax: Scalars['Int'] + taxRate: Scalars['Float'] +} + +export type ProductOptionGroup = Node & { + __typename?: 'ProductOptionGroup' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + code: Scalars['String'] + name: Scalars['String'] + options: Array + translations: Array + customFields?: Maybe +} + +export type ProductOptionGroupTranslation = { + __typename?: 'ProductOptionGroupTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] +} + +export type ProductOption = Node & { + __typename?: 'ProductOption' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + code: Scalars['String'] + name: Scalars['String'] + groupId: Scalars['ID'] + group: ProductOptionGroup + translations: Array + customFields?: Maybe +} + +export type ProductOptionTranslation = { + __typename?: 'ProductOptionTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] +} + +export type SearchReindexResponse = { + __typename?: 'SearchReindexResponse' + success: Scalars['Boolean'] +} + +export type SearchResponse = { + __typename?: 'SearchResponse' + items: Array + totalItems: Scalars['Int'] + facetValues: Array +} + +/** + * Which FacetValues are present in the products returned + * by the search, and in what quantity. + */ +export type FacetValueResult = { + __typename?: 'FacetValueResult' + facetValue: FacetValue + count: Scalars['Int'] +} + +export type SearchResultAsset = { + __typename?: 'SearchResultAsset' + id: Scalars['ID'] + preview: Scalars['String'] + focalPoint?: Maybe +} + +export type SearchResult = { + __typename?: 'SearchResult' + sku: Scalars['String'] + slug: Scalars['String'] + productId: Scalars['ID'] + productName: Scalars['String'] + /** @deprecated Use `productAsset.preview` instead */ + productPreview: Scalars['String'] + productAsset?: Maybe + productVariantId: Scalars['ID'] + productVariantName: Scalars['String'] + /** @deprecated Use `productVariantAsset.preview` instead */ + productVariantPreview: Scalars['String'] + productVariantAsset?: Maybe + price: SearchResultPrice + priceWithTax: SearchResultPrice + currencyCode: CurrencyCode + description: Scalars['String'] + facetIds: Array + facetValueIds: Array + /** An array of ids of the Collections in which this result appears */ + collectionIds: Array + /** A relevence score for the result. Differs between database implementations */ + score: Scalars['Float'] +} + +/** The price of a search result product, either as a range or as a single price */ +export type SearchResultPrice = PriceRange | SinglePrice + +/** The price value where the result has a single price */ +export type SinglePrice = { + __typename?: 'SinglePrice' + value: Scalars['Int'] +} + +/** The price range where the result has more than one price */ +export type PriceRange = { + __typename?: 'PriceRange' + min: Scalars['Int'] + max: Scalars['Int'] +} + +export type Product = Node & { + __typename?: 'Product' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] + slug: Scalars['String'] + description: Scalars['String'] + featuredAsset?: Maybe + assets: Array + variants: Array + optionGroups: Array + facetValues: Array + translations: Array + collections: Array + customFields?: Maybe +} + +export type ProductTranslation = { + __typename?: 'ProductTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] + slug: Scalars['String'] + description: Scalars['String'] +} + +export type ProductList = PaginatedList & { + __typename?: 'ProductList' + items: Array + totalItems: Scalars['Int'] +} + +export type ProductVariant = Node & { + __typename?: 'ProductVariant' + id: Scalars['ID'] + product: Product + productId: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + sku: Scalars['String'] + name: Scalars['String'] + featuredAsset?: Maybe + assets: Array + price: Scalars['Int'] + currencyCode: CurrencyCode + /** @deprecated price now always excludes tax */ + priceIncludesTax: Scalars['Boolean'] + priceWithTax: Scalars['Int'] + stockLevel: Scalars['String'] + taxRateApplied: TaxRate + taxCategory: TaxCategory + options: Array + facetValues: Array + translations: Array + customFields?: Maybe +} + +export type ProductVariantTranslation = { + __typename?: 'ProductVariantTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] +} + +export type Promotion = Node & { + __typename?: 'Promotion' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + startsAt?: Maybe + endsAt?: Maybe + couponCode?: Maybe + perCustomerUsageLimit?: Maybe + name: Scalars['String'] + enabled: Scalars['Boolean'] + conditions: Array + actions: Array +} + +export type PromotionList = PaginatedList & { + __typename?: 'PromotionList' + items: Array + totalItems: Scalars['Int'] +} + +export type Role = Node & { + __typename?: 'Role' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + code: Scalars['String'] + description: Scalars['String'] + permissions: Array + channels: Array +} + +export type RoleList = PaginatedList & { + __typename?: 'RoleList' + items: Array + totalItems: Scalars['Int'] +} + +export type ShippingMethod = Node & { + __typename?: 'ShippingMethod' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + code: Scalars['String'] + name: Scalars['String'] + description: Scalars['String'] + fulfillmentHandlerCode: Scalars['String'] + checker: ConfigurableOperation + calculator: ConfigurableOperation + translations: Array + customFields?: Maybe +} + +export type ShippingMethodTranslation = { + __typename?: 'ShippingMethodTranslation' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + languageCode: LanguageCode + name: Scalars['String'] + description: Scalars['String'] +} + +export type ShippingMethodList = PaginatedList & { + __typename?: 'ShippingMethodList' + items: Array + totalItems: Scalars['Int'] +} + +export type Tag = Node & { + __typename?: 'Tag' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + value: Scalars['String'] +} + +export type TagList = PaginatedList & { + __typename?: 'TagList' + items: Array + totalItems: Scalars['Int'] +} + +export type TaxCategory = Node & { + __typename?: 'TaxCategory' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + name: Scalars['String'] + isDefault: Scalars['Boolean'] +} + +export type TaxRate = Node & { + __typename?: 'TaxRate' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + name: Scalars['String'] + enabled: Scalars['Boolean'] + value: Scalars['Float'] + category: TaxCategory + zone: Zone + customerGroup?: Maybe +} + +export type TaxRateList = PaginatedList & { + __typename?: 'TaxRateList' + items: Array + totalItems: Scalars['Int'] +} + +export type User = Node & { + __typename?: 'User' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + identifier: Scalars['String'] + verified: Scalars['Boolean'] + roles: Array + lastLogin?: Maybe + authenticationMethods: Array + customFields?: Maybe +} + +export type AuthenticationMethod = Node & { + __typename?: 'AuthenticationMethod' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + strategy: Scalars['String'] +} + +export type Zone = Node & { + __typename?: 'Zone' + id: Scalars['ID'] + createdAt: Scalars['DateTime'] + updatedAt: Scalars['DateTime'] + name: Scalars['String'] + members: Array +} + +/** Returned when attempting to modify the contents of an Order that is not in the `AddingItems` state. */ +export type OrderModificationError = ErrorResult & { + __typename?: 'OrderModificationError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** Returned when attempting to set a ShippingMethod for which the Order is not eligible */ +export type IneligibleShippingMethodError = ErrorResult & { + __typename?: 'IneligibleShippingMethodError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** Returned when attempting to add a Payment to an Order that is not in the `ArrangingPayment` state. */ +export type OrderPaymentStateError = ErrorResult & { + __typename?: 'OrderPaymentStateError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** Returned when attempting to add a Payment using a PaymentMethod for which the Order is not eligible. */ +export type IneligiblePaymentMethodError = ErrorResult & { + __typename?: 'IneligiblePaymentMethodError' + errorCode: ErrorCode + message: Scalars['String'] + eligibilityCheckerMessage?: Maybe +} + +/** Returned when a Payment fails due to an error. */ +export type PaymentFailedError = ErrorResult & { + __typename?: 'PaymentFailedError' + errorCode: ErrorCode + message: Scalars['String'] + paymentErrorMessage: Scalars['String'] +} + +/** Returned when a Payment is declined by the payment provider. */ +export type PaymentDeclinedError = ErrorResult & { + __typename?: 'PaymentDeclinedError' + errorCode: ErrorCode + message: Scalars['String'] + paymentErrorMessage: Scalars['String'] +} + +/** Returned if the provided coupon code is invalid */ +export type CouponCodeInvalidError = ErrorResult & { + __typename?: 'CouponCodeInvalidError' + errorCode: ErrorCode + message: Scalars['String'] + couponCode: Scalars['String'] +} + +/** Returned if the provided coupon code is invalid */ +export type CouponCodeExpiredError = ErrorResult & { + __typename?: 'CouponCodeExpiredError' + errorCode: ErrorCode + message: Scalars['String'] + couponCode: Scalars['String'] +} + +/** Returned if the provided coupon code is invalid */ +export type CouponCodeLimitError = ErrorResult & { + __typename?: 'CouponCodeLimitError' + errorCode: ErrorCode + message: Scalars['String'] + couponCode: Scalars['String'] + limit: Scalars['Int'] +} + +/** Retured when attemting to set the Customer for an Order when already logged in. */ +export type AlreadyLoggedInError = ErrorResult & { + __typename?: 'AlreadyLoggedInError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** Retured when attemting to register or verify a customer account without a password, when one is required. */ +export type MissingPasswordError = ErrorResult & { + __typename?: 'MissingPasswordError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** Retured when attemting to verify a customer account with a password, when a password has already been set. */ +export type PasswordAlreadySetError = ErrorResult & { + __typename?: 'PasswordAlreadySetError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** + * Retured if the verification token (used to verify a Customer's email address) is either + * invalid or does not match any expected tokens. + */ +export type VerificationTokenInvalidError = ErrorResult & { + __typename?: 'VerificationTokenInvalidError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** + * Returned if the verification token (used to verify a Customer's email address) is valid, but has + * expired according to the `verificationTokenDuration` setting in the AuthOptions. + */ +export type VerificationTokenExpiredError = ErrorResult & { + __typename?: 'VerificationTokenExpiredError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** + * Retured if the token used to change a Customer's email address is either + * invalid or does not match any expected tokens. + */ +export type IdentifierChangeTokenInvalidError = ErrorResult & { + __typename?: 'IdentifierChangeTokenInvalidError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** + * Retured if the token used to change a Customer's email address is valid, but has + * expired according to the `verificationTokenDuration` setting in the AuthOptions. + */ +export type IdentifierChangeTokenExpiredError = ErrorResult & { + __typename?: 'IdentifierChangeTokenExpiredError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** + * Retured if the token used to reset a Customer's password is either + * invalid or does not match any expected tokens. + */ +export type PasswordResetTokenInvalidError = ErrorResult & { + __typename?: 'PasswordResetTokenInvalidError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** + * Retured if the token used to reset a Customer's password is valid, but has + * expired according to the `verificationTokenDuration` setting in the AuthOptions. + */ +export type PasswordResetTokenExpiredError = ErrorResult & { + __typename?: 'PasswordResetTokenExpiredError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** + * Returned if `authOptions.requireVerification` is set to `true` (which is the default) + * and an unverified user attempts to authenticate. + */ +export type NotVerifiedError = ErrorResult & { + __typename?: 'NotVerifiedError' + errorCode: ErrorCode + message: Scalars['String'] +} + +/** + * Returned when invoking a mutation which depends on there being an active Order on the + * current session. + */ +export type NoActiveOrderError = ErrorResult & { + __typename?: 'NoActiveOrderError' + errorCode: ErrorCode + message: Scalars['String'] +} + +export type RegisterCustomerInput = { + emailAddress: Scalars['String'] + title?: Maybe + firstName?: Maybe + lastName?: Maybe + phoneNumber?: Maybe + password?: Maybe +} + +export type UpdateCustomerInput = { + title?: Maybe + firstName?: Maybe + lastName?: Maybe + phoneNumber?: Maybe + customFields?: Maybe +} + +/** Passed as input to the `addPaymentToOrder` mutation. */ +export type PaymentInput = { + /** This field should correspond to the `code` property of a PaymentMethodHandler. */ + method: Scalars['String'] + /** + * This field should contain arbitrary data passed to the specified PaymentMethodHandler's `createPayment()` method + * as the "metadata" argument. For example, it could contain an ID for the payment and other + * data generated by the payment provider. + */ + metadata: Scalars['JSON'] +} + +export type UpdateOrderItemsResult = + | Order + | OrderModificationError + | OrderLimitError + | NegativeQuantityError + | InsufficientStockError + +export type RemoveOrderItemsResult = Order | OrderModificationError + +export type SetOrderShippingMethodResult = + | Order + | OrderModificationError + | IneligibleShippingMethodError + | NoActiveOrderError + +export type ApplyCouponCodeResult = + | Order + | CouponCodeExpiredError + | CouponCodeInvalidError + | CouponCodeLimitError + +export type AddPaymentToOrderResult = + | Order + | OrderPaymentStateError + | IneligiblePaymentMethodError + | PaymentFailedError + | PaymentDeclinedError + | OrderStateTransitionError + | NoActiveOrderError + +export type TransitionOrderToStateResult = Order | OrderStateTransitionError + +export type SetCustomerForOrderResult = + | Order + | AlreadyLoggedInError + | EmailAddressConflictError + | NoActiveOrderError + +export type RegisterCustomerAccountResult = + | Success + | MissingPasswordError + | NativeAuthStrategyError + +export type RefreshCustomerVerificationResult = + | Success + | NativeAuthStrategyError + +export type VerifyCustomerAccountResult = + | CurrentUser + | VerificationTokenInvalidError + | VerificationTokenExpiredError + | MissingPasswordError + | PasswordAlreadySetError + | NativeAuthStrategyError + +export type UpdateCustomerPasswordResult = + | Success + | InvalidCredentialsError + | NativeAuthStrategyError + +export type RequestUpdateCustomerEmailAddressResult = + | Success + | InvalidCredentialsError + | EmailAddressConflictError + | NativeAuthStrategyError + +export type UpdateCustomerEmailAddressResult = + | Success + | IdentifierChangeTokenInvalidError + | IdentifierChangeTokenExpiredError + | NativeAuthStrategyError + +export type RequestPasswordResetResult = Success | NativeAuthStrategyError + +export type ResetPasswordResult = + | CurrentUser + | PasswordResetTokenInvalidError + | PasswordResetTokenExpiredError + | NativeAuthStrategyError + +export type NativeAuthenticationResult = + | CurrentUser + | InvalidCredentialsError + | NotVerifiedError + | NativeAuthStrategyError + +export type AuthenticationResult = + | CurrentUser + | InvalidCredentialsError + | NotVerifiedError + +export type ActiveOrderResult = Order | NoActiveOrderError + +export type CollectionListOptions = { + skip?: Maybe + take?: Maybe + sort?: Maybe + filter?: Maybe +} + +export type ProductListOptions = { + skip?: Maybe + take?: Maybe + sort?: Maybe + filter?: Maybe +} + +export type ProductVariantListOptions = { + skip?: Maybe + take?: Maybe + sort?: Maybe + filter?: Maybe +} + +export type CustomerListOptions = { + skip?: Maybe + take?: Maybe + sort?: Maybe + filter?: Maybe +} + +export type OrderListOptions = { + skip?: Maybe + take?: Maybe + sort?: Maybe + filter?: Maybe +} + +export type HistoryEntryListOptions = { + skip?: Maybe + take?: Maybe + sort?: Maybe + filter?: Maybe +} + +export type CollectionFilterParameter = { + createdAt?: Maybe + updatedAt?: Maybe + languageCode?: Maybe + name?: Maybe + slug?: Maybe + position?: Maybe + description?: Maybe +} + +export type CollectionSortParameter = { + id?: Maybe + createdAt?: Maybe + updatedAt?: Maybe + name?: Maybe + slug?: Maybe + position?: Maybe + description?: Maybe +} + +export type ProductFilterParameter = { + createdAt?: Maybe + updatedAt?: Maybe + languageCode?: Maybe + name?: Maybe + slug?: Maybe + description?: Maybe +} + +export type ProductSortParameter = { + id?: Maybe + createdAt?: Maybe + updatedAt?: Maybe + name?: Maybe + slug?: Maybe + description?: Maybe +} + +export type ProductVariantFilterParameter = { + createdAt?: Maybe + updatedAt?: Maybe + languageCode?: Maybe + sku?: Maybe + name?: Maybe + price?: Maybe + currencyCode?: Maybe + priceIncludesTax?: Maybe + priceWithTax?: Maybe + stockLevel?: Maybe +} + +export type ProductVariantSortParameter = { + id?: Maybe + productId?: Maybe + createdAt?: Maybe + updatedAt?: Maybe + sku?: Maybe + name?: Maybe + price?: Maybe + priceWithTax?: Maybe + stockLevel?: Maybe +} + +export type CustomerFilterParameter = { + createdAt?: Maybe + updatedAt?: Maybe + title?: Maybe + firstName?: Maybe + lastName?: Maybe + phoneNumber?: Maybe + emailAddress?: Maybe +} + +export type CustomerSortParameter = { + id?: Maybe + createdAt?: Maybe + updatedAt?: Maybe + title?: Maybe + firstName?: Maybe + lastName?: Maybe + phoneNumber?: Maybe + emailAddress?: Maybe +} + +export type OrderFilterParameter = { + createdAt?: Maybe + updatedAt?: Maybe + orderPlacedAt?: Maybe + code?: Maybe + state?: Maybe + active?: Maybe + totalQuantity?: Maybe + subTotal?: Maybe + subTotalWithTax?: Maybe + currencyCode?: Maybe + shipping?: Maybe + shippingWithTax?: Maybe + total?: Maybe + totalWithTax?: Maybe +} + +export type OrderSortParameter = { + id?: Maybe + createdAt?: Maybe + updatedAt?: Maybe + orderPlacedAt?: Maybe + code?: Maybe + state?: Maybe + totalQuantity?: Maybe + subTotal?: Maybe + subTotalWithTax?: Maybe + shipping?: Maybe + shippingWithTax?: Maybe + total?: Maybe + totalWithTax?: Maybe +} + +export type HistoryEntryFilterParameter = { + createdAt?: Maybe + updatedAt?: Maybe + type?: Maybe +} + +export type HistoryEntrySortParameter = { + id?: Maybe + createdAt?: Maybe + updatedAt?: Maybe +} + +export type UpdateOrderInput = { + customFields?: Maybe +} + +export type AuthenticationInput = { + native?: Maybe +} + +export type NativeAuthInput = { + username: Scalars['String'] + password: Scalars['String'] +} + +export type CartFragment = { __typename?: 'Order' } & Pick< + Order, + | 'id' + | 'code' + | 'createdAt' + | 'totalQuantity' + | 'subTotal' + | 'subTotalWithTax' + | 'total' + | 'totalWithTax' + | 'currencyCode' +> & { + customer?: Maybe<{ __typename?: 'Customer' } & Pick> + lines: Array< + { __typename?: 'OrderLine' } & Pick< + OrderLine, + 'id' | 'quantity' | 'linePriceWithTax' | 'discountedLinePriceWithTax' + > & { + featuredAsset?: Maybe< + { __typename?: 'Asset' } & Pick + > + discounts: Array< + { __typename?: 'Adjustment' } & Pick< + Adjustment, + 'description' | 'amount' + > + > + productVariant: { __typename?: 'ProductVariant' } & Pick< + ProductVariant, + | 'id' + | 'name' + | 'sku' + | 'price' + | 'priceWithTax' + | 'stockLevel' + | 'productId' + > & { product: { __typename?: 'Product' } & Pick } + } + > + } + +export type SearchResultFragment = { __typename?: 'SearchResult' } & Pick< + SearchResult, + 'productId' | 'productName' | 'description' | 'slug' | 'sku' | 'currencyCode' +> & { + productAsset?: Maybe< + { __typename?: 'SearchResultAsset' } & Pick< + SearchResultAsset, + 'id' | 'preview' + > + > + priceWithTax: + | ({ __typename?: 'PriceRange' } & Pick) + | ({ __typename?: 'SinglePrice' } & Pick) + } + +export type LoginMutationVariables = Exact<{ + username: Scalars['String'] + password: Scalars['String'] +}> + +export type LoginMutation = { __typename?: 'Mutation' } & { + login: + | ({ __typename: 'CurrentUser' } & Pick) + | ({ __typename: 'InvalidCredentialsError' } & Pick< + InvalidCredentialsError, + 'errorCode' | 'message' + >) + | ({ __typename: 'NotVerifiedError' } & Pick< + NotVerifiedError, + 'errorCode' | 'message' + >) + | ({ __typename: 'NativeAuthStrategyError' } & Pick< + NativeAuthStrategyError, + 'errorCode' | 'message' + >) +} + +export type LogoutMutationVariables = Exact<{ [key: string]: never }> + +export type LogoutMutation = { __typename?: 'Mutation' } & { + logout: { __typename?: 'Success' } & Pick +} + +export type SignupMutationVariables = Exact<{ + input: RegisterCustomerInput +}> + +export type SignupMutation = { __typename?: 'Mutation' } & { + registerCustomerAccount: + | ({ __typename: 'Success' } & Pick) + | ({ __typename: 'MissingPasswordError' } & Pick< + MissingPasswordError, + 'errorCode' | 'message' + >) + | ({ __typename: 'NativeAuthStrategyError' } & Pick< + NativeAuthStrategyError, + 'errorCode' | 'message' + >) +} + +export type AddItemToOrderMutationVariables = Exact<{ + variantId: Scalars['ID'] + quantity: Scalars['Int'] +}> + +export type AddItemToOrderMutation = { __typename?: 'Mutation' } & { + addItemToOrder: + | ({ __typename: 'Order' } & CartFragment) + | ({ __typename: 'OrderModificationError' } & Pick< + OrderModificationError, + 'errorCode' | 'message' + >) + | ({ __typename: 'OrderLimitError' } & Pick< + OrderLimitError, + 'errorCode' | 'message' + >) + | ({ __typename: 'NegativeQuantityError' } & Pick< + NegativeQuantityError, + 'errorCode' | 'message' + >) + | ({ __typename: 'InsufficientStockError' } & Pick< + InsufficientStockError, + 'errorCode' | 'message' + >) +} + +export type ActiveOrderQueryVariables = Exact<{ [key: string]: never }> + +export type ActiveOrderQuery = { __typename?: 'Query' } & { + activeOrder?: Maybe<{ __typename?: 'Order' } & CartFragment> +} + +export type RemoveOrderLineMutationVariables = Exact<{ + orderLineId: Scalars['ID'] +}> + +export type RemoveOrderLineMutation = { __typename?: 'Mutation' } & { + removeOrderLine: + | ({ __typename: 'Order' } & CartFragment) + | ({ __typename: 'OrderModificationError' } & Pick< + OrderModificationError, + 'errorCode' | 'message' + >) +} + +export type AdjustOrderLineMutationVariables = Exact<{ + orderLineId: Scalars['ID'] + quantity: Scalars['Int'] +}> + +export type AdjustOrderLineMutation = { __typename?: 'Mutation' } & { + adjustOrderLine: + | ({ __typename: 'Order' } & CartFragment) + | ({ __typename: 'OrderModificationError' } & Pick< + OrderModificationError, + 'errorCode' | 'message' + >) + | ({ __typename: 'OrderLimitError' } & Pick< + OrderLimitError, + 'errorCode' | 'message' + >) + | ({ __typename: 'NegativeQuantityError' } & Pick< + NegativeQuantityError, + 'errorCode' | 'message' + >) + | ({ __typename: 'InsufficientStockError' } & Pick< + InsufficientStockError, + 'errorCode' | 'message' + >) +} + +export type GetCollectionsQueryVariables = Exact<{ [key: string]: never }> + +export type GetCollectionsQuery = { __typename?: 'Query' } & { + collections: { __typename?: 'CollectionList' } & { + items: Array< + { __typename?: 'Collection' } & Pick< + Collection, + 'id' | 'name' | 'description' | 'slug' + > & { + productVariants: { __typename?: 'ProductVariantList' } & Pick< + ProductVariantList, + 'totalItems' + > + parent?: Maybe<{ __typename?: 'Collection' } & Pick> + children?: Maybe< + Array<{ __typename?: 'Collection' } & Pick> + > + } + > + } +} + +export type ActiveCustomerQueryVariables = Exact<{ [key: string]: never }> + +export type ActiveCustomerQuery = { __typename?: 'Query' } & { + activeCustomer?: Maybe< + { __typename?: 'Customer' } & Pick< + Customer, + 'id' | 'firstName' | 'lastName' | 'emailAddress' + > + > +} + +export type GetAllProductPathsQueryVariables = Exact<{ + first?: Maybe +}> + +export type GetAllProductPathsQuery = { __typename?: 'Query' } & { + products: { __typename?: 'ProductList' } & { + items: Array<{ __typename?: 'Product' } & Pick> + } +} + +export type GetAllProductsQueryVariables = Exact<{ + input: SearchInput +}> + +export type GetAllProductsQuery = { __typename?: 'Query' } & { + search: { __typename?: 'SearchResponse' } & { + items: Array<{ __typename?: 'SearchResult' } & SearchResultFragment> + } +} + +export type GetProductQueryVariables = Exact<{ + slug: Scalars['String'] +}> + +export type GetProductQuery = { __typename?: 'Query' } & { + product?: Maybe< + { __typename?: 'Product' } & Pick< + Product, + 'id' | 'name' | 'slug' | 'description' + > & { + assets: Array< + { __typename?: 'Asset' } & Pick + > + variants: Array< + { __typename?: 'ProductVariant' } & Pick< + ProductVariant, + 'id' | 'priceWithTax' | 'currencyCode' + > & { + options: Array< + { __typename?: 'ProductOption' } & Pick< + ProductOption, + 'id' | 'name' | 'code' | 'groupId' + > & { + group: { __typename?: 'ProductOptionGroup' } & Pick< + ProductOptionGroup, + 'id' + > & { + options: Array< + { __typename?: 'ProductOption' } & Pick< + ProductOption, + 'name' + > + > + } + } + > + } + > + optionGroups: Array< + { __typename?: 'ProductOptionGroup' } & Pick< + ProductOptionGroup, + 'id' | 'code' | 'name' + > & { + options: Array< + { __typename?: 'ProductOption' } & Pick< + ProductOption, + 'id' | 'name' + > + > + } + > + } + > +} + +export type SearchQueryVariables = Exact<{ + input: SearchInput +}> + +export type SearchQuery = { __typename?: 'Query' } & { + search: { __typename?: 'SearchResponse' } & Pick< + SearchResponse, + 'totalItems' + > & { items: Array<{ __typename?: 'SearchResult' } & SearchResultFragment> } +} diff --git a/framework/vendure/schema.graphql b/framework/vendure/schema.graphql new file mode 100644 index 00000000..88812044 --- /dev/null +++ b/framework/vendure/schema.graphql @@ -0,0 +1,3860 @@ +type Query { + """ + The active Channel + """ + activeChannel: Channel! + + """ + The active Customer + """ + activeCustomer: Customer + + """ + The active Order. Will be `null` until an Order is created via `addItemToOrder`. Once an Order reaches the + state of `PaymentApproved` or `PaymentSettled`, then that Order is no longer considered "active" and this + query will once again return `null`. + """ + activeOrder: Order + + """ + An array of supported Countries + """ + availableCountries: [Country!]! + + """ + A list of Collections available to the shop + """ + collections(options: CollectionListOptions): CollectionList! + + """ + Returns a Collection either by its id or slug. If neither 'id' nor 'slug' is speicified, an error will result. + """ + collection(id: ID, slug: String): Collection + + """ + Returns a list of eligible shipping methods based on the current active Order + """ + eligibleShippingMethods: [ShippingMethodQuote!]! + + """ + Returns a list of payment methods and their eligibility based on the current active Order + """ + eligiblePaymentMethods: [PaymentMethodQuote!]! + + """ + Returns information about the current authenticated User + """ + me: CurrentUser + + """ + Returns the possible next states that the activeOrder can transition to + """ + nextOrderStates: [String!]! + + """ + Returns an Order based on the id. Note that in the Shop API, only orders belonging to the + currently-authenticated User may be queried. + """ + order(id: ID!): Order + + """ + Returns an Order based on the order `code`. For guest Orders (i.e. Orders placed by non-authenticated Customers) + this query will only return the Order within 2 hours of the Order being placed. This allows an Order confirmation + screen to be shown immediately after completion of a guest checkout, yet prevents security risks of allowing + general anonymous access to Order data. + """ + orderByCode(code: String!): Order + + """ + Get a Product either by id or slug. If neither 'id' nor 'slug' is speicified, an error will result. + """ + product(id: ID, slug: String): Product + + """ + Get a list of Products + """ + products(options: ProductListOptions): ProductList! + + """ + Search Products based on the criteria set by the `SearchInput` + """ + search(input: SearchInput!): SearchResponse! +} + +type Mutation { + """ + Adds an item to the order. If custom fields are defined on the OrderLine entity, a third argument 'customFields' will be available. + """ + addItemToOrder(productVariantId: ID!, quantity: Int!): UpdateOrderItemsResult! + + """ + Remove an OrderLine from the Order + """ + removeOrderLine(orderLineId: ID!): RemoveOrderItemsResult! + + """ + Remove all OrderLine from the Order + """ + removeAllOrderLines: RemoveOrderItemsResult! + + """ + Adjusts an OrderLine. If custom fields are defined on the OrderLine entity, a third argument 'customFields' of type `OrderLineCustomFieldsInput` will be available. + """ + adjustOrderLine(orderLineId: ID!, quantity: Int!): UpdateOrderItemsResult! + + """ + Applies the given coupon code to the active Order + """ + applyCouponCode(couponCode: String!): ApplyCouponCodeResult! + + """ + Removes the given coupon code from the active Order + """ + removeCouponCode(couponCode: String!): Order + + """ + Transitions an Order to a new state. Valid next states can be found by querying `nextOrderStates` + """ + transitionOrderToState(state: String!): TransitionOrderToStateResult + + """ + Sets the shipping address for this order + """ + setOrderShippingAddress(input: CreateAddressInput!): ActiveOrderResult! + + """ + Sets the billing address for this order + """ + setOrderBillingAddress(input: CreateAddressInput!): ActiveOrderResult! + + """ + Allows any custom fields to be set for the active order + """ + setOrderCustomFields(input: UpdateOrderInput!): ActiveOrderResult! + + """ + Sets the shipping method by id, which can be obtained with the `eligibleShippingMethods` query + """ + setOrderShippingMethod(shippingMethodId: ID!): SetOrderShippingMethodResult! + + """ + Add a Payment to the Order + """ + addPaymentToOrder(input: PaymentInput!): AddPaymentToOrderResult! + + """ + Set the Customer for the Order. Required only if the Customer is not currently logged in + """ + setCustomerForOrder(input: CreateCustomerInput!): SetCustomerForOrderResult! + + """ + Authenticates the user using the native authentication strategy. This mutation is an alias for `authenticate({ native: { ... }})` + """ + login( + username: String! + password: String! + rememberMe: Boolean + ): NativeAuthenticationResult! + + """ + Authenticates the user using a named authentication strategy + """ + authenticate( + input: AuthenticationInput! + rememberMe: Boolean + ): AuthenticationResult! + + """ + End the current authenticated session + """ + logout: Success! + + """ + Register a Customer account with the given credentials. There are three possible registration flows: + + _If `authOptions.requireVerification` is set to `true`:_ + + 1. **The Customer is registered _with_ a password**. A verificationToken will be created (and typically emailed to the Customer). That + verificationToken would then be passed to the `verifyCustomerAccount` mutation _without_ a password. The Customer is then + verified and authenticated in one step. + 2. **The Customer is registered _without_ a password**. A verificationToken will be created (and typically emailed to the Customer). That + verificationToken would then be passed to the `verifyCustomerAccount` mutation _with_ the chosed password of the Customer. The Customer is then + verified and authenticated in one step. + + _If `authOptions.requireVerification` is set to `false`:_ + + 3. The Customer _must_ be registered _with_ a password. No further action is needed - the Customer is able to authenticate immediately. + """ + registerCustomerAccount( + input: RegisterCustomerInput! + ): RegisterCustomerAccountResult! + + """ + Regenerate and send a verification token for a new Customer registration. Only applicable if `authOptions.requireVerification` is set to true. + """ + refreshCustomerVerification( + emailAddress: String! + ): RefreshCustomerVerificationResult! + + """ + Update an existing Customer + """ + updateCustomer(input: UpdateCustomerInput!): Customer! + + """ + Create a new Customer Address + """ + createCustomerAddress(input: CreateAddressInput!): Address! + + """ + Update an existing Address + """ + updateCustomerAddress(input: UpdateAddressInput!): Address! + + """ + Delete an existing Address + """ + deleteCustomerAddress(id: ID!): Success! + + """ + Verify a Customer email address with the token sent to that address. Only applicable if `authOptions.requireVerification` is set to true. + + If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the a password _must_ be + provided here. + """ + verifyCustomerAccount( + token: String! + password: String + ): VerifyCustomerAccountResult! + + """ + Update the password of the active Customer + """ + updateCustomerPassword( + currentPassword: String! + newPassword: String! + ): UpdateCustomerPasswordResult! + + """ + Request to update the emailAddress of the active Customer. If `authOptions.requireVerification` is enabled + (as is the default), then the `identifierChangeToken` will be assigned to the current User and + a IdentifierChangeRequestEvent will be raised. This can then be used e.g. by the EmailPlugin to email + that verification token to the Customer, which is then used to verify the change of email address. + """ + requestUpdateCustomerEmailAddress( + password: String! + newEmailAddress: String! + ): RequestUpdateCustomerEmailAddressResult! + + """ + Confirm the update of the emailAddress with the provided token, which has been generated by the + `requestUpdateCustomerEmailAddress` mutation. + """ + updateCustomerEmailAddress(token: String!): UpdateCustomerEmailAddressResult! + + """ + Requests a password reset email to be sent + """ + requestPasswordReset(emailAddress: String!): RequestPasswordResetResult + + """ + Resets a Customer's password based on the provided token + """ + resetPassword(token: String!, password: String!): ResetPasswordResult! +} + +type Address implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + fullName: String + company: String + streetLine1: String! + streetLine2: String + city: String + province: String + postalCode: String + country: Country! + phoneNumber: String + defaultShippingAddress: Boolean + defaultBillingAddress: Boolean + customFields: JSON +} + +type Asset implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + name: String! + type: AssetType! + fileSize: Int! + mimeType: String! + width: Int! + height: Int! + source: String! + preview: String! + focalPoint: Coordinate + customFields: JSON +} + +type Coordinate { + x: Float! + y: Float! +} + +type AssetList implements PaginatedList { + items: [Asset!]! + totalItems: Int! +} + +enum AssetType { + IMAGE + VIDEO + BINARY +} + +type CurrentUser { + id: ID! + identifier: String! + channels: [CurrentUserChannel!]! +} + +type CurrentUserChannel { + id: ID! + token: String! + code: String! + permissions: [Permission!]! +} + +type Channel implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + code: String! + token: String! + defaultTaxZone: Zone + defaultShippingZone: Zone + defaultLanguageCode: LanguageCode! + currencyCode: CurrencyCode! + pricesIncludeTax: Boolean! + customFields: JSON +} + +type Collection implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode + name: String! + slug: String! + breadcrumbs: [CollectionBreadcrumb!]! + position: Int! + description: String! + featuredAsset: Asset + assets: [Asset!]! + parent: Collection + children: [Collection!] + filters: [ConfigurableOperation!]! + translations: [CollectionTranslation!]! + productVariants(options: ProductVariantListOptions): ProductVariantList! + customFields: JSON +} + +type CollectionBreadcrumb { + id: ID! + name: String! + slug: String! +} + +type CollectionTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! + slug: String! + description: String! +} + +type CollectionList implements PaginatedList { + items: [Collection!]! + totalItems: Int! +} + +type ProductVariantList implements PaginatedList { + items: [ProductVariant!]! + totalItems: Int! +} + +enum GlobalFlag { + TRUE + FALSE + INHERIT +} + +enum AdjustmentType { + PROMOTION + DISTRIBUTED_ORDER_PROMOTION +} + +enum DeletionResult { + """ + The entity was successfully deleted + """ + DELETED + + """ + Deletion did not take place, reason given in message + """ + NOT_DELETED +} + +""" +@description +Permissions for administrators and customers. Used to control access to +GraphQL resolvers via the {@link Allow} decorator. + +@docsCategory common +""" +enum Permission { + """ + Authenticated means simply that the user is logged in + """ + Authenticated + + """ + SuperAdmin has unrestricted access to all operations + """ + SuperAdmin + + """ + Owner means the user owns this entity, e.g. a Customer's own Order + """ + Owner + + """ + Public means any unauthenticated user may perform the operation + """ + Public + + """ + Grants permission to create Catalog + """ + CreateCatalog + + """ + Grants permission to read Catalog + """ + ReadCatalog + + """ + Grants permission to update Catalog + """ + UpdateCatalog + + """ + Grants permission to delete Catalog + """ + DeleteCatalog + + """ + Grants permission to create Customer + """ + CreateCustomer + + """ + Grants permission to read Customer + """ + ReadCustomer + + """ + Grants permission to update Customer + """ + UpdateCustomer + + """ + Grants permission to delete Customer + """ + DeleteCustomer + + """ + Grants permission to create Administrator + """ + CreateAdministrator + + """ + Grants permission to read Administrator + """ + ReadAdministrator + + """ + Grants permission to update Administrator + """ + UpdateAdministrator + + """ + Grants permission to delete Administrator + """ + DeleteAdministrator + + """ + Grants permission to create Order + """ + CreateOrder + + """ + Grants permission to read Order + """ + ReadOrder + + """ + Grants permission to update Order + """ + UpdateOrder + + """ + Grants permission to delete Order + """ + DeleteOrder + + """ + Grants permission to create Promotion + """ + CreatePromotion + + """ + Grants permission to read Promotion + """ + ReadPromotion + + """ + Grants permission to update Promotion + """ + UpdatePromotion + + """ + Grants permission to delete Promotion + """ + DeletePromotion + + """ + Grants permission to create Settings + """ + CreateSettings + + """ + Grants permission to read Settings + """ + ReadSettings + + """ + Grants permission to update Settings + """ + UpdateSettings + + """ + Grants permission to delete Settings + """ + DeleteSettings +} + +enum SortOrder { + ASC + DESC +} + +enum ErrorCode { + UNKNOWN_ERROR + NATIVE_AUTH_STRATEGY_ERROR + INVALID_CREDENTIALS_ERROR + ORDER_STATE_TRANSITION_ERROR + EMAIL_ADDRESS_CONFLICT_ERROR + ORDER_LIMIT_ERROR + NEGATIVE_QUANTITY_ERROR + INSUFFICIENT_STOCK_ERROR + ORDER_MODIFICATION_ERROR + INELIGIBLE_SHIPPING_METHOD_ERROR + ORDER_PAYMENT_STATE_ERROR + INELIGIBLE_PAYMENT_METHOD_ERROR + PAYMENT_FAILED_ERROR + PAYMENT_DECLINED_ERROR + COUPON_CODE_INVALID_ERROR + COUPON_CODE_EXPIRED_ERROR + COUPON_CODE_LIMIT_ERROR + ALREADY_LOGGED_IN_ERROR + MISSING_PASSWORD_ERROR + PASSWORD_ALREADY_SET_ERROR + VERIFICATION_TOKEN_INVALID_ERROR + VERIFICATION_TOKEN_EXPIRED_ERROR + IDENTIFIER_CHANGE_TOKEN_INVALID_ERROR + IDENTIFIER_CHANGE_TOKEN_EXPIRED_ERROR + PASSWORD_RESET_TOKEN_INVALID_ERROR + PASSWORD_RESET_TOKEN_EXPIRED_ERROR + NOT_VERIFIED_ERROR + NO_ACTIVE_ORDER_ERROR +} + +enum LogicalOperator { + AND + OR +} + +""" +Retured when attempting an operation that relies on the NativeAuthStrategy, if that strategy is not configured. +""" +type NativeAuthStrategyError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Returned if the user authentication credentials are not valid +""" +type InvalidCredentialsError implements ErrorResult { + errorCode: ErrorCode! + message: String! + authenticationError: String! +} + +""" +Returned if there is an error in transitioning the Order state +""" +type OrderStateTransitionError implements ErrorResult { + errorCode: ErrorCode! + message: String! + transitionError: String! + fromState: String! + toState: String! +} + +""" +Retured when attemting to create a Customer with an email address already registered to an existing User. +""" +type EmailAddressConflictError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Retured when the maximum order size limit has been reached. +""" +type OrderLimitError implements ErrorResult { + errorCode: ErrorCode! + message: String! + maxItems: Int! +} + +""" +Retured when attemting to set a negative OrderLine quantity. +""" +type NegativeQuantityError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Returned when attempting to add more items to the Order than are available +""" +type InsufficientStockError implements ErrorResult { + errorCode: ErrorCode! + message: String! + quantityAvailable: Int! + order: Order! +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar DateTime + +""" +The `Upload` scalar type represents a file upload. +""" +scalar Upload + +interface PaginatedList { + items: [Node!]! + totalItems: Int! +} + +interface Node { + id: ID! +} + +interface ErrorResult { + errorCode: ErrorCode! + message: String! +} + +type Adjustment { + adjustmentSource: String! + type: AdjustmentType! + description: String! + amount: Int! +} + +type TaxLine { + description: String! + taxRate: Float! +} + +type ConfigArg { + name: String! + value: String! +} + +type ConfigArgDefinition { + name: String! + type: String! + list: Boolean! + required: Boolean! + defaultValue: JSON + label: String + description: String + ui: JSON +} + +type ConfigurableOperation { + code: String! + args: [ConfigArg!]! +} + +type ConfigurableOperationDefinition { + code: String! + args: [ConfigArgDefinition!]! + description: String! +} + +type DeletionResponse { + result: DeletionResult! + message: String +} + +input ConfigArgInput { + name: String! + + """ + A JSON stringified representation of the actual value + """ + value: String! +} + +input ConfigurableOperationInput { + code: String! + arguments: [ConfigArgInput!]! +} + +input StringOperators { + eq: String + notEq: String + contains: String + notContains: String + in: [String!] + notIn: [String!] + regex: String +} + +input BooleanOperators { + eq: Boolean +} + +input NumberRange { + start: Float! + end: Float! +} + +input NumberOperators { + eq: Float + lt: Float + lte: Float + gt: Float + gte: Float + between: NumberRange +} + +input DateRange { + start: DateTime! + end: DateTime! +} + +input DateOperators { + eq: DateTime + before: DateTime + after: DateTime + between: DateRange +} + +input SearchInput { + term: String + facetValueIds: [ID!] + facetValueOperator: LogicalOperator + collectionId: ID + collectionSlug: String + groupByProduct: Boolean + take: Int + skip: Int + sort: SearchResultSortParameter +} + +input SearchResultSortParameter { + name: SortOrder + price: SortOrder +} + +input CreateCustomerInput { + title: String + firstName: String! + lastName: String! + phoneNumber: String + emailAddress: String! + customFields: JSON +} + +input CreateAddressInput { + fullName: String + company: String + streetLine1: String! + streetLine2: String + city: String + province: String + postalCode: String + countryCode: String! + phoneNumber: String + defaultShippingAddress: Boolean + defaultBillingAddress: Boolean + customFields: JSON +} + +input UpdateAddressInput { + id: ID! + fullName: String + company: String + streetLine1: String + streetLine2: String + city: String + province: String + postalCode: String + countryCode: String + phoneNumber: String + defaultShippingAddress: Boolean + defaultBillingAddress: Boolean + customFields: JSON +} + +""" +Indicates that an operation succeeded, where we do not want to return any more specific information. +""" +type Success { + success: Boolean! +} + +type ShippingMethodQuote { + id: ID! + price: Int! + priceWithTax: Int! + name: String! + description: String! + + """ + Any optional metadata returned by the ShippingCalculator in the ShippingCalculationResult + """ + metadata: JSON +} + +type PaymentMethodQuote { + id: ID! + code: String! + isEligible: Boolean! + eligibilityMessage: String +} + +type Country implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + code: String! + name: String! + enabled: Boolean! + translations: [CountryTranslation!]! +} + +type CountryTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! +} + +type CountryList implements PaginatedList { + items: [Country!]! + totalItems: Int! +} + +""" +@description +ISO 4217 currency code + +@docsCategory common +""" +enum CurrencyCode { + """ + United Arab Emirates dirham + """ + AED + + """ + Afghan afghani + """ + AFN + + """ + Albanian lek + """ + ALL + + """ + Armenian dram + """ + AMD + + """ + Netherlands Antillean guilder + """ + ANG + + """ + Angolan kwanza + """ + AOA + + """ + Argentine peso + """ + ARS + + """ + Australian dollar + """ + AUD + + """ + Aruban florin + """ + AWG + + """ + Azerbaijani manat + """ + AZN + + """ + Bosnia and Herzegovina convertible mark + """ + BAM + + """ + Barbados dollar + """ + BBD + + """ + Bangladeshi taka + """ + BDT + + """ + Bulgarian lev + """ + BGN + + """ + Bahraini dinar + """ + BHD + + """ + Burundian franc + """ + BIF + + """ + Bermudian dollar + """ + BMD + + """ + Brunei dollar + """ + BND + + """ + Boliviano + """ + BOB + + """ + Brazilian real + """ + BRL + + """ + Bahamian dollar + """ + BSD + + """ + Bhutanese ngultrum + """ + BTN + + """ + Botswana pula + """ + BWP + + """ + Belarusian ruble + """ + BYN + + """ + Belize dollar + """ + BZD + + """ + Canadian dollar + """ + CAD + + """ + Congolese franc + """ + CDF + + """ + Swiss franc + """ + CHF + + """ + Chilean peso + """ + CLP + + """ + Renminbi (Chinese) yuan + """ + CNY + + """ + Colombian peso + """ + COP + + """ + Costa Rican colon + """ + CRC + + """ + Cuban convertible peso + """ + CUC + + """ + Cuban peso + """ + CUP + + """ + Cape Verde escudo + """ + CVE + + """ + Czech koruna + """ + CZK + + """ + Djiboutian franc + """ + DJF + + """ + Danish krone + """ + DKK + + """ + Dominican peso + """ + DOP + + """ + Algerian dinar + """ + DZD + + """ + Egyptian pound + """ + EGP + + """ + Eritrean nakfa + """ + ERN + + """ + Ethiopian birr + """ + ETB + + """ + Euro + """ + EUR + + """ + Fiji dollar + """ + FJD + + """ + Falkland Islands pound + """ + FKP + + """ + Pound sterling + """ + GBP + + """ + Georgian lari + """ + GEL + + """ + Ghanaian cedi + """ + GHS + + """ + Gibraltar pound + """ + GIP + + """ + Gambian dalasi + """ + GMD + + """ + Guinean franc + """ + GNF + + """ + Guatemalan quetzal + """ + GTQ + + """ + Guyanese dollar + """ + GYD + + """ + Hong Kong dollar + """ + HKD + + """ + Honduran lempira + """ + HNL + + """ + Croatian kuna + """ + HRK + + """ + Haitian gourde + """ + HTG + + """ + Hungarian forint + """ + HUF + + """ + Indonesian rupiah + """ + IDR + + """ + Israeli new shekel + """ + ILS + + """ + Indian rupee + """ + INR + + """ + Iraqi dinar + """ + IQD + + """ + Iranian rial + """ + IRR + + """ + Icelandic króna + """ + ISK + + """ + Jamaican dollar + """ + JMD + + """ + Jordanian dinar + """ + JOD + + """ + Japanese yen + """ + JPY + + """ + Kenyan shilling + """ + KES + + """ + Kyrgyzstani som + """ + KGS + + """ + Cambodian riel + """ + KHR + + """ + Comoro franc + """ + KMF + + """ + North Korean won + """ + KPW + + """ + South Korean won + """ + KRW + + """ + Kuwaiti dinar + """ + KWD + + """ + Cayman Islands dollar + """ + KYD + + """ + Kazakhstani tenge + """ + KZT + + """ + Lao kip + """ + LAK + + """ + Lebanese pound + """ + LBP + + """ + Sri Lankan rupee + """ + LKR + + """ + Liberian dollar + """ + LRD + + """ + Lesotho loti + """ + LSL + + """ + Libyan dinar + """ + LYD + + """ + Moroccan dirham + """ + MAD + + """ + Moldovan leu + """ + MDL + + """ + Malagasy ariary + """ + MGA + + """ + Macedonian denar + """ + MKD + + """ + Myanmar kyat + """ + MMK + + """ + Mongolian tögrög + """ + MNT + + """ + Macanese pataca + """ + MOP + + """ + Mauritanian ouguiya + """ + MRU + + """ + Mauritian rupee + """ + MUR + + """ + Maldivian rufiyaa + """ + MVR + + """ + Malawian kwacha + """ + MWK + + """ + Mexican peso + """ + MXN + + """ + Malaysian ringgit + """ + MYR + + """ + Mozambican metical + """ + MZN + + """ + Namibian dollar + """ + NAD + + """ + Nigerian naira + """ + NGN + + """ + Nicaraguan córdoba + """ + NIO + + """ + Norwegian krone + """ + NOK + + """ + Nepalese rupee + """ + NPR + + """ + New Zealand dollar + """ + NZD + + """ + Omani rial + """ + OMR + + """ + Panamanian balboa + """ + PAB + + """ + Peruvian sol + """ + PEN + + """ + Papua New Guinean kina + """ + PGK + + """ + Philippine peso + """ + PHP + + """ + Pakistani rupee + """ + PKR + + """ + Polish złoty + """ + PLN + + """ + Paraguayan guaraní + """ + PYG + + """ + Qatari riyal + """ + QAR + + """ + Romanian leu + """ + RON + + """ + Serbian dinar + """ + RSD + + """ + Russian ruble + """ + RUB + + """ + Rwandan franc + """ + RWF + + """ + Saudi riyal + """ + SAR + + """ + Solomon Islands dollar + """ + SBD + + """ + Seychelles rupee + """ + SCR + + """ + Sudanese pound + """ + SDG + + """ + Swedish krona/kronor + """ + SEK + + """ + Singapore dollar + """ + SGD + + """ + Saint Helena pound + """ + SHP + + """ + Sierra Leonean leone + """ + SLL + + """ + Somali shilling + """ + SOS + + """ + Surinamese dollar + """ + SRD + + """ + South Sudanese pound + """ + SSP + + """ + São Tomé and Príncipe dobra + """ + STN + + """ + Salvadoran colón + """ + SVC + + """ + Syrian pound + """ + SYP + + """ + Swazi lilangeni + """ + SZL + + """ + Thai baht + """ + THB + + """ + Tajikistani somoni + """ + TJS + + """ + Turkmenistan manat + """ + TMT + + """ + Tunisian dinar + """ + TND + + """ + Tongan paʻanga + """ + TOP + + """ + Turkish lira + """ + TRY + + """ + Trinidad and Tobago dollar + """ + TTD + + """ + New Taiwan dollar + """ + TWD + + """ + Tanzanian shilling + """ + TZS + + """ + Ukrainian hryvnia + """ + UAH + + """ + Ugandan shilling + """ + UGX + + """ + United States dollar + """ + USD + + """ + Uruguayan peso + """ + UYU + + """ + Uzbekistan som + """ + UZS + + """ + Venezuelan bolívar soberano + """ + VES + + """ + Vietnamese đồng + """ + VND + + """ + Vanuatu vatu + """ + VUV + + """ + Samoan tala + """ + WST + + """ + CFA franc BEAC + """ + XAF + + """ + East Caribbean dollar + """ + XCD + + """ + CFA franc BCEAO + """ + XOF + + """ + CFP franc (franc Pacifique) + """ + XPF + + """ + Yemeni rial + """ + YER + + """ + South African rand + """ + ZAR + + """ + Zambian kwacha + """ + ZMW + + """ + Zimbabwean dollar + """ + ZWL +} + +interface CustomField { + name: String! + type: String! + list: Boolean! + label: [LocalizedString!] + description: [LocalizedString!] + readonly: Boolean + internal: Boolean +} + +type StringCustomFieldConfig implements CustomField { + name: String! + type: String! + list: Boolean! + length: Int + label: [LocalizedString!] + description: [LocalizedString!] + readonly: Boolean + internal: Boolean + pattern: String + options: [StringFieldOption!] +} + +type StringFieldOption { + value: String! + label: [LocalizedString!] +} + +type LocaleStringCustomFieldConfig implements CustomField { + name: String! + type: String! + list: Boolean! + length: Int + label: [LocalizedString!] + description: [LocalizedString!] + readonly: Boolean + internal: Boolean + pattern: String +} + +type IntCustomFieldConfig implements CustomField { + name: String! + type: String! + list: Boolean! + label: [LocalizedString!] + description: [LocalizedString!] + readonly: Boolean + internal: Boolean + min: Int + max: Int + step: Int +} + +type FloatCustomFieldConfig implements CustomField { + name: String! + type: String! + list: Boolean! + label: [LocalizedString!] + description: [LocalizedString!] + readonly: Boolean + internal: Boolean + min: Float + max: Float + step: Float +} + +type BooleanCustomFieldConfig implements CustomField { + name: String! + type: String! + list: Boolean! + label: [LocalizedString!] + description: [LocalizedString!] + readonly: Boolean + internal: Boolean +} + +""" +Expects the same validation formats as the `` HTML element. +See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local#Additional_attributes +""" +type DateTimeCustomFieldConfig implements CustomField { + name: String! + type: String! + list: Boolean! + label: [LocalizedString!] + description: [LocalizedString!] + readonly: Boolean + internal: Boolean + min: String + max: String + step: Int +} + +type RelationCustomFieldConfig implements CustomField { + name: String! + type: String! + list: Boolean! + label: [LocalizedString!] + description: [LocalizedString!] + readonly: Boolean + internal: Boolean + entity: String! + scalarFields: [String!]! +} + +type LocalizedString { + languageCode: LanguageCode! + value: String! +} + +union CustomFieldConfig = + StringCustomFieldConfig + | LocaleStringCustomFieldConfig + | IntCustomFieldConfig + | FloatCustomFieldConfig + | BooleanCustomFieldConfig + | DateTimeCustomFieldConfig + | RelationCustomFieldConfig + +type CustomerGroup implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + name: String! + customers(options: CustomerListOptions): CustomerList! +} + +type Customer implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + title: String + firstName: String! + lastName: String! + phoneNumber: String + emailAddress: String! + addresses: [Address!] + orders(options: OrderListOptions): OrderList! + user: User + customFields: JSON +} + +type CustomerList implements PaginatedList { + items: [Customer!]! + totalItems: Int! +} + +type FacetValue implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + facet: Facet! + name: String! + code: String! + translations: [FacetValueTranslation!]! + customFields: JSON +} + +type FacetValueTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! +} + +type Facet implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! + code: String! + values: [FacetValue!]! + translations: [FacetTranslation!]! + customFields: JSON +} + +type FacetTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! +} + +type FacetList implements PaginatedList { + items: [Facet!]! + totalItems: Int! +} + +type HistoryEntry implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + type: HistoryEntryType! + data: JSON! +} + +enum HistoryEntryType { + CUSTOMER_REGISTERED + CUSTOMER_VERIFIED + CUSTOMER_DETAIL_UPDATED + CUSTOMER_ADDED_TO_GROUP + CUSTOMER_REMOVED_FROM_GROUP + CUSTOMER_ADDRESS_CREATED + CUSTOMER_ADDRESS_UPDATED + CUSTOMER_ADDRESS_DELETED + CUSTOMER_PASSWORD_UPDATED + CUSTOMER_PASSWORD_RESET_REQUESTED + CUSTOMER_PASSWORD_RESET_VERIFIED + CUSTOMER_EMAIL_UPDATE_REQUESTED + CUSTOMER_EMAIL_UPDATE_VERIFIED + CUSTOMER_NOTE + ORDER_STATE_TRANSITION + ORDER_PAYMENT_TRANSITION + ORDER_FULFILLMENT + ORDER_CANCELLATION + ORDER_REFUND_TRANSITION + ORDER_FULFILLMENT_TRANSITION + ORDER_NOTE + ORDER_COUPON_APPLIED + ORDER_COUPON_REMOVED + ORDER_MODIFIED +} + +type HistoryEntryList implements PaginatedList { + items: [HistoryEntry!]! + totalItems: Int! +} + +""" +@description +Languages in the form of a ISO 639-1 language code with optional +region or script modifier (e.g. de_AT). The selection available is based +on the [Unicode CLDR summary list](https://unicode-org.github.io/cldr-staging/charts/37/summary/root.html) +and includes the major spoken languages of the world and any widely-used variants. + +@docsCategory common +""" +enum LanguageCode { + """ + Afrikaans + """ + af + + """ + Akan + """ + ak + + """ + Albanian + """ + sq + + """ + Amharic + """ + am + + """ + Arabic + """ + ar + + """ + Armenian + """ + hy + + """ + Assamese + """ + as + + """ + Azerbaijani + """ + az + + """ + Bambara + """ + bm + + """ + Bangla + """ + bn + + """ + Basque + """ + eu + + """ + Belarusian + """ + be + + """ + Bosnian + """ + bs + + """ + Breton + """ + br + + """ + Bulgarian + """ + bg + + """ + Burmese + """ + my + + """ + Catalan + """ + ca + + """ + Chechen + """ + ce + + """ + Chinese + """ + zh + + """ + Simplified Chinese + """ + zh_Hans + + """ + Traditional Chinese + """ + zh_Hant + + """ + Church Slavic + """ + cu + + """ + Cornish + """ + kw + + """ + Corsican + """ + co + + """ + Croatian + """ + hr + + """ + Czech + """ + cs + + """ + Danish + """ + da + + """ + Dutch + """ + nl + + """ + Flemish + """ + nl_BE + + """ + Dzongkha + """ + dz + + """ + English + """ + en + + """ + Australian English + """ + en_AU + + """ + Canadian English + """ + en_CA + + """ + British English + """ + en_GB + + """ + American English + """ + en_US + + """ + Esperanto + """ + eo + + """ + Estonian + """ + et + + """ + Ewe + """ + ee + + """ + Faroese + """ + fo + + """ + Finnish + """ + fi + + """ + French + """ + fr + + """ + Canadian French + """ + fr_CA + + """ + Swiss French + """ + fr_CH + + """ + Fulah + """ + ff + + """ + Galician + """ + gl + + """ + Ganda + """ + lg + + """ + Georgian + """ + ka + + """ + German + """ + de + + """ + Austrian German + """ + de_AT + + """ + Swiss High German + """ + de_CH + + """ + Greek + """ + el + + """ + Gujarati + """ + gu + + """ + Haitian Creole + """ + ht + + """ + Hausa + """ + ha + + """ + Hebrew + """ + he + + """ + Hindi + """ + hi + + """ + Hungarian + """ + hu + + """ + Icelandic + """ + is + + """ + Igbo + """ + ig + + """ + Indonesian + """ + id + + """ + Interlingua + """ + ia + + """ + Irish + """ + ga + + """ + Italian + """ + it + + """ + Japanese + """ + ja + + """ + Javanese + """ + jv + + """ + Kalaallisut + """ + kl + + """ + Kannada + """ + kn + + """ + Kashmiri + """ + ks + + """ + Kazakh + """ + kk + + """ + Khmer + """ + km + + """ + Kikuyu + """ + ki + + """ + Kinyarwanda + """ + rw + + """ + Korean + """ + ko + + """ + Kurdish + """ + ku + + """ + Kyrgyz + """ + ky + + """ + Lao + """ + lo + + """ + Latin + """ + la + + """ + Latvian + """ + lv + + """ + Lingala + """ + ln + + """ + Lithuanian + """ + lt + + """ + Luba-Katanga + """ + lu + + """ + Luxembourgish + """ + lb + + """ + Macedonian + """ + mk + + """ + Malagasy + """ + mg + + """ + Malay + """ + ms + + """ + Malayalam + """ + ml + + """ + Maltese + """ + mt + + """ + Manx + """ + gv + + """ + Maori + """ + mi + + """ + Marathi + """ + mr + + """ + Mongolian + """ + mn + + """ + Nepali + """ + ne + + """ + North Ndebele + """ + nd + + """ + Northern Sami + """ + se + + """ + Norwegian Bokmål + """ + nb + + """ + Norwegian Nynorsk + """ + nn + + """ + Nyanja + """ + ny + + """ + Odia + """ + or + + """ + Oromo + """ + om + + """ + Ossetic + """ + os + + """ + Pashto + """ + ps + + """ + Persian + """ + fa + + """ + Dari + """ + fa_AF + + """ + Polish + """ + pl + + """ + Portuguese + """ + pt + + """ + Brazilian Portuguese + """ + pt_BR + + """ + European Portuguese + """ + pt_PT + + """ + Punjabi + """ + pa + + """ + Quechua + """ + qu + + """ + Romanian + """ + ro + + """ + Moldavian + """ + ro_MD + + """ + Romansh + """ + rm + + """ + Rundi + """ + rn + + """ + Russian + """ + ru + + """ + Samoan + """ + sm + + """ + Sango + """ + sg + + """ + Sanskrit + """ + sa + + """ + Scottish Gaelic + """ + gd + + """ + Serbian + """ + sr + + """ + Shona + """ + sn + + """ + Sichuan Yi + """ + ii + + """ + Sindhi + """ + sd + + """ + Sinhala + """ + si + + """ + Slovak + """ + sk + + """ + Slovenian + """ + sl + + """ + Somali + """ + so + + """ + Southern Sotho + """ + st + + """ + Spanish + """ + es + + """ + European Spanish + """ + es_ES + + """ + Mexican Spanish + """ + es_MX + + """ + Sundanese + """ + su + + """ + Swahili + """ + sw + + """ + Congo Swahili + """ + sw_CD + + """ + Swedish + """ + sv + + """ + Tajik + """ + tg + + """ + Tamil + """ + ta + + """ + Tatar + """ + tt + + """ + Telugu + """ + te + + """ + Thai + """ + th + + """ + Tibetan + """ + bo + + """ + Tigrinya + """ + ti + + """ + Tongan + """ + to + + """ + Turkish + """ + tr + + """ + Turkmen + """ + tk + + """ + Ukrainian + """ + uk + + """ + Urdu + """ + ur + + """ + Uyghur + """ + ug + + """ + Uzbek + """ + uz + + """ + Vietnamese + """ + vi + + """ + Volapük + """ + vo + + """ + Welsh + """ + cy + + """ + Western Frisian + """ + fy + + """ + Wolof + """ + wo + + """ + Xhosa + """ + xh + + """ + Yiddish + """ + yi + + """ + Yoruba + """ + yo + + """ + Zulu + """ + zu +} + +type Order implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + + """ + The date & time that the Order was placed, i.e. the Customer + completed the checkout and the Order is no longer "active" + """ + orderPlacedAt: DateTime + + """ + A unique code for the Order + """ + code: String! + state: String! + + """ + An order is active as long as the payment process has not been completed + """ + active: Boolean! + customer: Customer + shippingAddress: OrderAddress + billingAddress: OrderAddress + lines: [OrderLine!]! + + """ + Surcharges are arbitrary modifications to the Order total which are neither + ProductVariants nor discounts resulting from applied Promotions. For example, + one-off discounts based on customer interaction, or surcharges based on payment + methods. + """ + surcharges: [Surcharge!]! + + """ + Order-level adjustments to the order total, such as discounts from promotions + """ + adjustments: [Adjustment!]! @deprecated(reason: "Use `discounts` instead") + discounts: [Adjustment!]! + + """ + An array of all coupon codes applied to the Order + """ + couponCodes: [String!]! + + """ + Promotions applied to the order. Only gets populated after the payment process has completed. + """ + promotions: [Promotion!]! + payments: [Payment!] + fulfillments: [Fulfillment!] + totalQuantity: Int! + + """ + The subTotal is the total of all OrderLines in the Order. This figure also includes any Order-level + discounts which have been prorated (proportionally distributed) amongst the OrderItems. + To get a total of all OrderLines which does not account for prorated discounts, use the + sum of `OrderLine.discountedLinePrice` values. + """ + subTotal: Int! + + """ + Same as subTotal, but inclusive of tax + """ + subTotalWithTax: Int! + currencyCode: CurrencyCode! + shippingLines: [ShippingLine!]! + shipping: Int! + shippingWithTax: Int! + + """ + Equal to subTotal plus shipping + """ + total: Int! + + """ + The final payable amount. Equal to subTotalWithTax plus shippingWithTax + """ + totalWithTax: Int! + + """ + A summary of the taxes being applied to this Order + """ + taxSummary: [OrderTaxSummary!]! + history(options: HistoryEntryListOptions): HistoryEntryList! + customFields: JSON +} + +""" +A summary of the taxes being applied to this order, grouped +by taxRate. +""" +type OrderTaxSummary { + """ + A description of this tax + """ + description: String! + + """ + The taxRate as a percentage + """ + taxRate: Float! + + """ + The total net price or OrderItems to which this taxRate applies + """ + taxBase: Int! + + """ + The total tax being applied to the Order at this taxRate + """ + taxTotal: Int! +} + +type OrderAddress { + fullName: String + company: String + streetLine1: String + streetLine2: String + city: String + province: String + postalCode: String + country: String + countryCode: String + phoneNumber: String + customFields: JSON +} + +type OrderList implements PaginatedList { + items: [Order!]! + totalItems: Int! +} + +type ShippingLine { + shippingMethod: ShippingMethod! + price: Int! + priceWithTax: Int! + discountedPrice: Int! + discountedPriceWithTax: Int! + discounts: [Adjustment!]! +} + +type OrderItem implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + cancelled: Boolean! + + """ + The price of a single unit, excluding tax and discounts + """ + unitPrice: Int! + + """ + The price of a single unit, including tax but excluding discounts + """ + unitPriceWithTax: Int! + + """ + The price of a single unit including discounts, excluding tax. + + If Order-level discounts have been applied, this will not be the + actual taxable unit price (see `proratedUnitPrice`), but is generally the + correct price to display to customers to avoid confusion + about the internal handling of distributed Order-level discounts. + """ + discountedUnitPrice: Int! + + """ + The price of a single unit including discounts and tax + """ + discountedUnitPriceWithTax: Int! + + """ + The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed) + Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax + and refund calculations. + """ + proratedUnitPrice: Int! + + """ + The proratedUnitPrice including tax + """ + proratedUnitPriceWithTax: Int! + unitTax: Int! + unitPriceIncludesTax: Boolean! + @deprecated(reason: "`unitPrice` is now always without tax") + taxRate: Float! + adjustments: [Adjustment!]! + taxLines: [TaxLine!]! + fulfillment: Fulfillment + refundId: ID +} + +type OrderLine implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + productVariant: ProductVariant! + featuredAsset: Asset + + """ + The price of a single unit, excluding tax and discounts + """ + unitPrice: Int! + + """ + The price of a single unit, including tax but excluding discounts + """ + unitPriceWithTax: Int! + + """ + Non-zero if the unitPrice has changed since it was initially added to Order + """ + unitPriceChangeSinceAdded: Int! + + """ + Non-zero if the unitPriceWithTax has changed since it was initially added to Order + """ + unitPriceWithTaxChangeSinceAdded: Int! + + """ + The price of a single unit including discounts, excluding tax. + + If Order-level discounts have been applied, this will not be the + actual taxable unit price (see `proratedUnitPrice`), but is generally the + correct price to display to customers to avoid confusion + about the internal handling of distributed Order-level discounts. + """ + discountedUnitPrice: Int! + + """ + The price of a single unit including discounts and tax + """ + discountedUnitPriceWithTax: Int! + + """ + The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed) + Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax + and refund calculations. + """ + proratedUnitPrice: Int! + + """ + The proratedUnitPrice including tax + """ + proratedUnitPriceWithTax: Int! + quantity: Int! + items: [OrderItem!]! + totalPrice: Int! @deprecated(reason: "Use `linePriceWithTax` instead") + taxRate: Float! + + """ + The total price of the line excluding tax and discounts. + """ + linePrice: Int! + + """ + The total price of the line including tax bit excluding discounts. + """ + linePriceWithTax: Int! + + """ + The price of the line including discounts, excluding tax + """ + discountedLinePrice: Int! + + """ + The price of the line including discounts and tax + """ + discountedLinePriceWithTax: Int! + + """ + The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed) + Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax + and refund calculations. + """ + proratedLinePrice: Int! + + """ + The proratedLinePrice including tax + """ + proratedLinePriceWithTax: Int! + + """ + The total tax on this line + """ + lineTax: Int! + adjustments: [Adjustment!]! @deprecated(reason: "Use `discounts` instead") + discounts: [Adjustment!]! + taxLines: [TaxLine!]! + order: Order! + customFields: JSON +} + +type Payment implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + method: String! + amount: Int! + state: String! + transactionId: String + errorMessage: String + refunds: [Refund!]! + metadata: JSON +} + +type Refund implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + items: Int! + shipping: Int! + adjustment: Int! + total: Int! + method: String + state: String! + transactionId: String + reason: String + orderItems: [OrderItem!]! + paymentId: ID! + metadata: JSON +} + +type Fulfillment implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + orderItems: [OrderItem!]! + state: String! + method: String! + trackingCode: String + customFields: JSON +} + +type Surcharge implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + description: String! + sku: String + taxLines: [TaxLine!]! + price: Int! + priceWithTax: Int! + taxRate: Float! +} + +type ProductOptionGroup implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + code: String! + name: String! + options: [ProductOption!]! + translations: [ProductOptionGroupTranslation!]! + customFields: JSON +} + +type ProductOptionGroupTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! +} + +type ProductOption implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + code: String! + name: String! + groupId: ID! + group: ProductOptionGroup! + translations: [ProductOptionTranslation!]! + customFields: JSON +} + +type ProductOptionTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! +} + +type SearchReindexResponse { + success: Boolean! +} + +type SearchResponse { + items: [SearchResult!]! + totalItems: Int! + facetValues: [FacetValueResult!]! +} + +""" +Which FacetValues are present in the products returned +by the search, and in what quantity. +""" +type FacetValueResult { + facetValue: FacetValue! + count: Int! +} + +type SearchResultAsset { + id: ID! + preview: String! + focalPoint: Coordinate +} + +type SearchResult { + sku: String! + slug: String! + productId: ID! + productName: String! + productPreview: String! + @deprecated(reason: "Use `productAsset.preview` instead") + productAsset: SearchResultAsset + productVariantId: ID! + productVariantName: String! + productVariantPreview: String! + @deprecated(reason: "Use `productVariantAsset.preview` instead") + productVariantAsset: SearchResultAsset + price: SearchResultPrice! + priceWithTax: SearchResultPrice! + currencyCode: CurrencyCode! + description: String! + facetIds: [ID!]! + facetValueIds: [ID!]! + + """ + An array of ids of the Collections in which this result appears + """ + collectionIds: [ID!]! + + """ + A relevence score for the result. Differs between database implementations + """ + score: Float! +} + +""" +The price of a search result product, either as a range or as a single price +""" +union SearchResultPrice = PriceRange | SinglePrice + +""" +The price value where the result has a single price +""" +type SinglePrice { + value: Int! +} + +""" +The price range where the result has more than one price +""" +type PriceRange { + min: Int! + max: Int! +} + +type Product implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! + slug: String! + description: String! + featuredAsset: Asset + assets: [Asset!]! + variants: [ProductVariant!]! + optionGroups: [ProductOptionGroup!]! + facetValues: [FacetValue!]! + translations: [ProductTranslation!]! + collections: [Collection!]! + customFields: JSON +} + +type ProductTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! + slug: String! + description: String! +} + +type ProductList implements PaginatedList { + items: [Product!]! + totalItems: Int! +} + +type ProductVariant implements Node { + id: ID! + product: Product! + productId: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + sku: String! + name: String! + featuredAsset: Asset + assets: [Asset!]! + price: Int! + currencyCode: CurrencyCode! + priceIncludesTax: Boolean! + @deprecated(reason: "price now always excludes tax") + priceWithTax: Int! + stockLevel: String! + taxRateApplied: TaxRate! + taxCategory: TaxCategory! + options: [ProductOption!]! + facetValues: [FacetValue!]! + translations: [ProductVariantTranslation!]! + customFields: JSON +} + +type ProductVariantTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! +} + +type Promotion implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + startsAt: DateTime + endsAt: DateTime + couponCode: String + perCustomerUsageLimit: Int + name: String! + enabled: Boolean! + conditions: [ConfigurableOperation!]! + actions: [ConfigurableOperation!]! +} + +type PromotionList implements PaginatedList { + items: [Promotion!]! + totalItems: Int! +} + +type Role implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + code: String! + description: String! + permissions: [Permission!]! + channels: [Channel!]! +} + +type RoleList implements PaginatedList { + items: [Role!]! + totalItems: Int! +} + +type ShippingMethod implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + code: String! + name: String! + description: String! + fulfillmentHandlerCode: String! + checker: ConfigurableOperation! + calculator: ConfigurableOperation! + translations: [ShippingMethodTranslation!]! + customFields: JSON +} + +type ShippingMethodTranslation { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + languageCode: LanguageCode! + name: String! + description: String! +} + +type ShippingMethodList implements PaginatedList { + items: [ShippingMethod!]! + totalItems: Int! +} + +type Tag implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + value: String! +} + +type TagList implements PaginatedList { + items: [Tag!]! + totalItems: Int! +} + +type TaxCategory implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + name: String! + isDefault: Boolean! +} + +type TaxRate implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + name: String! + enabled: Boolean! + value: Float! + category: TaxCategory! + zone: Zone! + customerGroup: CustomerGroup +} + +type TaxRateList implements PaginatedList { + items: [TaxRate!]! + totalItems: Int! +} + +type User implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + identifier: String! + verified: Boolean! + roles: [Role!]! + lastLogin: DateTime + authenticationMethods: [AuthenticationMethod!]! + customFields: JSON +} + +type AuthenticationMethod implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + strategy: String! +} + +type Zone implements Node { + id: ID! + createdAt: DateTime! + updatedAt: DateTime! + name: String! + members: [Country!]! +} + +""" +Returned when attempting to modify the contents of an Order that is not in the `AddingItems` state. +""" +type OrderModificationError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Returned when attempting to set a ShippingMethod for which the Order is not eligible +""" +type IneligibleShippingMethodError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Returned when attempting to add a Payment to an Order that is not in the `ArrangingPayment` state. +""" +type OrderPaymentStateError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Returned when attempting to add a Payment using a PaymentMethod for which the Order is not eligible. +""" +type IneligiblePaymentMethodError implements ErrorResult { + errorCode: ErrorCode! + message: String! + eligibilityCheckerMessage: String +} + +""" +Returned when a Payment fails due to an error. +""" +type PaymentFailedError implements ErrorResult { + errorCode: ErrorCode! + message: String! + paymentErrorMessage: String! +} + +""" +Returned when a Payment is declined by the payment provider. +""" +type PaymentDeclinedError implements ErrorResult { + errorCode: ErrorCode! + message: String! + paymentErrorMessage: String! +} + +""" +Returned if the provided coupon code is invalid +""" +type CouponCodeInvalidError implements ErrorResult { + errorCode: ErrorCode! + message: String! + couponCode: String! +} + +""" +Returned if the provided coupon code is invalid +""" +type CouponCodeExpiredError implements ErrorResult { + errorCode: ErrorCode! + message: String! + couponCode: String! +} + +""" +Returned if the provided coupon code is invalid +""" +type CouponCodeLimitError implements ErrorResult { + errorCode: ErrorCode! + message: String! + couponCode: String! + limit: Int! +} + +""" +Retured when attemting to set the Customer for an Order when already logged in. +""" +type AlreadyLoggedInError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Retured when attemting to register or verify a customer account without a password, when one is required. +""" +type MissingPasswordError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Retured when attemting to verify a customer account with a password, when a password has already been set. +""" +type PasswordAlreadySetError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Retured if the verification token (used to verify a Customer's email address) is either +invalid or does not match any expected tokens. +""" +type VerificationTokenInvalidError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Returned if the verification token (used to verify a Customer's email address) is valid, but has +expired according to the `verificationTokenDuration` setting in the AuthOptions. +""" +type VerificationTokenExpiredError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Retured if the token used to change a Customer's email address is either +invalid or does not match any expected tokens. +""" +type IdentifierChangeTokenInvalidError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Retured if the token used to change a Customer's email address is valid, but has +expired according to the `verificationTokenDuration` setting in the AuthOptions. +""" +type IdentifierChangeTokenExpiredError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Retured if the token used to reset a Customer's password is either +invalid or does not match any expected tokens. +""" +type PasswordResetTokenInvalidError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Retured if the token used to reset a Customer's password is valid, but has +expired according to the `verificationTokenDuration` setting in the AuthOptions. +""" +type PasswordResetTokenExpiredError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Returned if `authOptions.requireVerification` is set to `true` (which is the default) +and an unverified user attempts to authenticate. +""" +type NotVerifiedError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +""" +Returned when invoking a mutation which depends on there being an active Order on the +current session. +""" +type NoActiveOrderError implements ErrorResult { + errorCode: ErrorCode! + message: String! +} + +input RegisterCustomerInput { + emailAddress: String! + title: String + firstName: String + lastName: String + phoneNumber: String + password: String +} + +input UpdateCustomerInput { + title: String + firstName: String + lastName: String + phoneNumber: String + customFields: JSON +} + +""" +Passed as input to the `addPaymentToOrder` mutation. +""" +input PaymentInput { + """ + This field should correspond to the `code` property of a PaymentMethodHandler. + """ + method: String! + + """ + This field should contain arbitrary data passed to the specified PaymentMethodHandler's `createPayment()` method + as the "metadata" argument. For example, it could contain an ID for the payment and other + data generated by the payment provider. + """ + metadata: JSON! +} + +union UpdateOrderItemsResult = + Order + | OrderModificationError + | OrderLimitError + | NegativeQuantityError + | InsufficientStockError + +union RemoveOrderItemsResult = Order | OrderModificationError + +union SetOrderShippingMethodResult = + Order + | OrderModificationError + | IneligibleShippingMethodError + | NoActiveOrderError + +union ApplyCouponCodeResult = + Order + | CouponCodeExpiredError + | CouponCodeInvalidError + | CouponCodeLimitError + +union AddPaymentToOrderResult = + Order + | OrderPaymentStateError + | IneligiblePaymentMethodError + | PaymentFailedError + | PaymentDeclinedError + | OrderStateTransitionError + | NoActiveOrderError + +union TransitionOrderToStateResult = Order | OrderStateTransitionError + +union SetCustomerForOrderResult = + Order + | AlreadyLoggedInError + | EmailAddressConflictError + | NoActiveOrderError + +union RegisterCustomerAccountResult = + Success + | MissingPasswordError + | NativeAuthStrategyError + +union RefreshCustomerVerificationResult = Success | NativeAuthStrategyError + +union VerifyCustomerAccountResult = + CurrentUser + | VerificationTokenInvalidError + | VerificationTokenExpiredError + | MissingPasswordError + | PasswordAlreadySetError + | NativeAuthStrategyError + +union UpdateCustomerPasswordResult = + Success + | InvalidCredentialsError + | NativeAuthStrategyError + +union RequestUpdateCustomerEmailAddressResult = + Success + | InvalidCredentialsError + | EmailAddressConflictError + | NativeAuthStrategyError + +union UpdateCustomerEmailAddressResult = + Success + | IdentifierChangeTokenInvalidError + | IdentifierChangeTokenExpiredError + | NativeAuthStrategyError + +union RequestPasswordResetResult = Success | NativeAuthStrategyError + +union ResetPasswordResult = + CurrentUser + | PasswordResetTokenInvalidError + | PasswordResetTokenExpiredError + | NativeAuthStrategyError + +union NativeAuthenticationResult = + CurrentUser + | InvalidCredentialsError + | NotVerifiedError + | NativeAuthStrategyError + +union AuthenticationResult = + CurrentUser + | InvalidCredentialsError + | NotVerifiedError + +union ActiveOrderResult = Order | NoActiveOrderError + +input CollectionListOptions { + skip: Int + take: Int + sort: CollectionSortParameter + filter: CollectionFilterParameter +} + +input ProductListOptions { + skip: Int + take: Int + sort: ProductSortParameter + filter: ProductFilterParameter +} + +input ProductVariantListOptions { + skip: Int + take: Int + sort: ProductVariantSortParameter + filter: ProductVariantFilterParameter +} + +input CustomerListOptions { + skip: Int + take: Int + sort: CustomerSortParameter + filter: CustomerFilterParameter +} + +input OrderListOptions { + skip: Int + take: Int + sort: OrderSortParameter + filter: OrderFilterParameter +} + +input HistoryEntryListOptions { + skip: Int + take: Int + sort: HistoryEntrySortParameter + filter: HistoryEntryFilterParameter +} + +input CollectionFilterParameter { + createdAt: DateOperators + updatedAt: DateOperators + languageCode: StringOperators + name: StringOperators + slug: StringOperators + position: NumberOperators + description: StringOperators +} + +input CollectionSortParameter { + id: SortOrder + createdAt: SortOrder + updatedAt: SortOrder + name: SortOrder + slug: SortOrder + position: SortOrder + description: SortOrder +} + +input ProductFilterParameter { + createdAt: DateOperators + updatedAt: DateOperators + languageCode: StringOperators + name: StringOperators + slug: StringOperators + description: StringOperators +} + +input ProductSortParameter { + id: SortOrder + createdAt: SortOrder + updatedAt: SortOrder + name: SortOrder + slug: SortOrder + description: SortOrder +} + +input ProductVariantFilterParameter { + createdAt: DateOperators + updatedAt: DateOperators + languageCode: StringOperators + sku: StringOperators + name: StringOperators + price: NumberOperators + currencyCode: StringOperators + priceIncludesTax: BooleanOperators + priceWithTax: NumberOperators + stockLevel: StringOperators +} + +input ProductVariantSortParameter { + id: SortOrder + productId: SortOrder + createdAt: SortOrder + updatedAt: SortOrder + sku: SortOrder + name: SortOrder + price: SortOrder + priceWithTax: SortOrder + stockLevel: SortOrder +} + +input CustomerFilterParameter { + createdAt: DateOperators + updatedAt: DateOperators + title: StringOperators + firstName: StringOperators + lastName: StringOperators + phoneNumber: StringOperators + emailAddress: StringOperators +} + +input CustomerSortParameter { + id: SortOrder + createdAt: SortOrder + updatedAt: SortOrder + title: SortOrder + firstName: SortOrder + lastName: SortOrder + phoneNumber: SortOrder + emailAddress: SortOrder +} + +input OrderFilterParameter { + createdAt: DateOperators + updatedAt: DateOperators + orderPlacedAt: DateOperators + code: StringOperators + state: StringOperators + active: BooleanOperators + totalQuantity: NumberOperators + subTotal: NumberOperators + subTotalWithTax: NumberOperators + currencyCode: StringOperators + shipping: NumberOperators + shippingWithTax: NumberOperators + total: NumberOperators + totalWithTax: NumberOperators +} + +input OrderSortParameter { + id: SortOrder + createdAt: SortOrder + updatedAt: SortOrder + orderPlacedAt: SortOrder + code: SortOrder + state: SortOrder + totalQuantity: SortOrder + subTotal: SortOrder + subTotalWithTax: SortOrder + shipping: SortOrder + shippingWithTax: SortOrder + total: SortOrder + totalWithTax: SortOrder +} + +input HistoryEntryFilterParameter { + createdAt: DateOperators + updatedAt: DateOperators + type: StringOperators +} + +input HistoryEntrySortParameter { + id: SortOrder + createdAt: SortOrder + updatedAt: SortOrder +} + +input UpdateOrderInput { + customFields: JSON +} + +input AuthenticationInput { + native: NativeAuthInput +} + +input NativeAuthInput { + username: String! + password: String! +} diff --git a/framework/vendure/types.ts b/framework/vendure/types.ts new file mode 100644 index 00000000..ed39b549 --- /dev/null +++ b/framework/vendure/types.ts @@ -0,0 +1,5 @@ +import * as Core from '@commerce/types' + +export interface LineItem extends Core.LineItem { + options?: any[] +} diff --git a/framework/vendure/wishlist/use-add-item.tsx b/framework/vendure/wishlist/use-add-item.tsx new file mode 100644 index 00000000..75f067c3 --- /dev/null +++ b/framework/vendure/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/framework/vendure/wishlist/use-remove-item.tsx b/framework/vendure/wishlist/use-remove-item.tsx new file mode 100644 index 00000000..a2d3a8a0 --- /dev/null +++ b/framework/vendure/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/framework/vendure/wishlist/use-wishlist.tsx b/framework/vendure/wishlist/use-wishlist.tsx new file mode 100644 index 00000000..d2ce9db5 --- /dev/null +++ b/framework/vendure/wishlist/use-wishlist.tsx @@ -0,0 +1,46 @@ +// TODO: replace this hook and other wishlist hooks with a handler, or remove them if +// Shopify doesn't have a wishlist + +import { HookFetcher } from '@commerce/utils/types' +import { Product } from '../schema' + +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/global.d.ts b/global.d.ts new file mode 100644 index 00000000..498a1f9f --- /dev/null +++ b/global.d.ts @@ -0,0 +1,2 @@ +// Declarations for modules without types +declare module 'next-themes' diff --git a/lib/click-outside/click-outside.tsx b/lib/click-outside/click-outside.tsx new file mode 100644 index 00000000..3c6b0ef2 --- /dev/null +++ b/lib/click-outside/click-outside.tsx @@ -0,0 +1,42 @@ +import React, { useRef, useEffect, MouseEvent } from 'react' +import hasParent from './has-parent' + +interface ClickOutsideProps { + active: boolean + onClick: (e?: MouseEvent) => void + children: any +} + +const ClickOutside = ({ + active = true, + onClick, + children, +}: ClickOutsideProps) => { + const innerRef = useRef() + + const handleClick = (event: any) => { + if (!hasParent(event.target, innerRef?.current)) { + if (typeof onClick === 'function') { + onClick(event) + } + } + } + + useEffect(() => { + if (active) { + document.addEventListener('mousedown', handleClick) + document.addEventListener('touchstart', handleClick) + } + + return () => { + if (active) { + document.removeEventListener('mousedown', handleClick) + document.removeEventListener('touchstart', handleClick) + } + } + }) + + return React.cloneElement(children, { ref: innerRef }) +} + +export default ClickOutside diff --git a/lib/click-outside/has-parent.js b/lib/click-outside/has-parent.js new file mode 100644 index 00000000..06cd3ca9 --- /dev/null +++ b/lib/click-outside/has-parent.js @@ -0,0 +1,5 @@ +import isInDOM from './is-in-dom' + +export default function hasParent(element, root) { + return root && root.contains(element) && isInDOM(element) +} diff --git a/lib/click-outside/index.ts b/lib/click-outside/index.ts new file mode 100644 index 00000000..2df916f9 --- /dev/null +++ b/lib/click-outside/index.ts @@ -0,0 +1 @@ +export { default } from './click-outside' diff --git a/lib/click-outside/is-in-dom.js b/lib/click-outside/is-in-dom.js new file mode 100644 index 00000000..5d7438ed --- /dev/null +++ b/lib/click-outside/is-in-dom.js @@ -0,0 +1,3 @@ +export default function isInDom(obj) { + return Boolean(obj.closest('body')) +} diff --git a/lib/colors.ts b/lib/colors.ts new file mode 100644 index 00000000..139cda23 --- /dev/null +++ b/lib/colors.ts @@ -0,0 +1,202 @@ +import random from 'lodash.random' + +export function getRandomPairOfColors() { + const colors = ['#37B679', '#DA3C3C', '#3291FF', '#7928CA', '#79FFE1'] + const getRandomIdx = () => random(0, colors.length - 1) + let idx = getRandomIdx() + let idx2 = getRandomIdx() + + // Has to be a different color + while (idx2 === idx) { + idx2 = getRandomIdx() + } + + // Returns a pair of colors + return [colors[idx], colors[idx2]] +} + +function hexToRgb(hex: string = '') { + // @ts-ignore + const match = hex.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i) + + if (!match) { + return [0, 0, 0] + } + + let colorString = match[0] + + if (match[0].length === 3) { + colorString = colorString + .split('') + .map((char: string) => { + return char + char + }) + .join('') + } + + const integer = parseInt(colorString, 16) + const r = (integer >> 16) & 0xff + const g = (integer >> 8) & 0xff + const b = integer & 0xff + + return [r, g, b] +} + +const colorMap: Record = { + aliceblue: '#F0F8FF', + antiquewhite: '#FAEBD7', + aqua: '#00FFFF', + aquamarine: '#7FFFD4', + azure: '#F0FFFF', + beige: '#F5F5DC', + bisque: '#FFE4C4', + black: '#000000', + blanchedalmond: '#FFEBCD', + blue: '#0000FF', + blueviolet: '#8A2BE2', + brown: '#A52A2A', + burlywood: '#DEB887', + cadetblue: '#5F9EA0', + chartreuse: '#7FFF00', + chocolate: '#D2691E', + coral: '#FF7F50', + cornflowerblue: '#6495ED', + cornsilk: '#FFF8DC', + crimson: '#DC143C', + cyan: '#00FFFF', + darkblue: '#00008B', + darkcyan: '#008B8B', + darkgoldenrod: '#B8860B', + darkgray: '#A9A9A9', + darkgreen: '#006400', + darkgrey: '#A9A9A9', + darkkhaki: '#BDB76B', + darkmagenta: '#8B008B', + darkolivegreen: '#556B2F', + darkorange: '#FF8C00', + darkorchid: '#9932CC', + darkred: '#8B0000', + darksalmon: '#E9967A', + darkseagreen: '#8FBC8F', + darkslateblue: '#483D8B', + darkslategray: '#2F4F4F', + darkslategrey: '#2F4F4F', + darkturquoise: '#00CED1', + darkviolet: '#9400D3', + deeppink: '#FF1493', + deepskyblue: '#00BFFF', + dimgray: '#696969', + dimgrey: '#696969', + dodgerblue: '#1E90FF', + firebrick: '#B22222', + floralwhite: '#FFFAF0', + forestgreen: '#228B22', + fuchsia: '#FF00FF', + gainsboro: '#DCDCDC', + ghostwhite: '#F8F8FF', + gold: '#FFD700', + goldenrod: '#DAA520', + gray: '#808080', + green: '#008000', + greenyellow: '#ADFF2F', + grey: '#808080', + honeydew: '#F0FFF0', + hotpink: '#FF69B4', + indianred: '#CD5C5C', + indigo: '#4B0082', + ivory: '#FFFFF0', + khaki: '#F0E68C', + lavender: '#E6E6FA', + lavenderblush: '#FFF0F5', + lawngreen: '#7CFC00', + lemonchiffon: '#FFFACD', + lightblue: '#ADD8E6', + lightcoral: '#F08080', + lightcyan: '#E0FFFF', + lightgoldenrodyellow: '#FAFAD2', + lightgray: '#D3D3D3', + lightgreen: '#90EE90', + lightgrey: '#D3D3D3', + lightpink: '#FFB6C1', + lightsalmon: '#FFA07A', + lightseagreen: '#20B2AA', + lightskyblue: '#87CEFA', + lightslategray: '#778899', + lightslategrey: '#778899', + lightsteelblue: '#B0C4DE', + lightyellow: '#FFFFE0', + lime: '#00FF00', + limegreen: '#32CD32', + linen: '#FAF0E6', + magenta: '#FF00FF', + maroon: '#800000', + mediumaquamarine: '#66CDAA', + mediumblue: '#0000CD', + mediumorchid: '#BA55D3', + mediumpurple: '#9370DB', + mediumseagreen: '#3CB371', + mediumslateblue: '#7B68EE', + mediumspringgreen: '#00FA9A', + mediumturquoise: '#48D1CC', + mediumvioletred: '#C71585', + midnightblue: '#191970', + mintcream: '#F5FFFA', + mistyrose: '#FFE4E1', + moccasin: '#FFE4B5', + navajowhite: '#FFDEAD', + navy: '#000080', + oldlace: '#FDF5E6', + olive: '#808000', + olivedrab: '#6B8E23', + orange: '#FFA500', + orangered: '#FF4500', + orchid: '#DA70D6', + palegoldenrod: '#EEE8AA', + palegreen: '#98FB98', + paleturquoise: '#AFEEEE', + palevioletred: '#DB7093', + papayawhip: '#FFEFD5', + peachpuff: '#FFDAB9', + peru: '#CD853F', + pink: '#FFC0CB', + plum: '#DDA0DD', + powderblue: '#B0E0E6', + purple: '#800080', + rebeccapurple: '#663399', + red: '#FF0000', + rosybrown: '#BC8F8F', + royalblue: '#4169E1', + saddlebrown: '#8B4513', + salmon: '#FA8072', + sandybrown: '#F4A460', + seagreen: '#2E8B57', + seashell: '#FFF5EE', + sienna: '#A0522D', + silver: '#C0C0C0', + skyblue: '#87CEEB', + slateblue: '#6A5ACD', + slategray: '#708090', + slategrey: '#708090', + snow: '#FFFAFA', + springgreen: '#00FF7F', + steelblue: '#4682B4', + tan: '#D2B48C', + teal: '#008080', + thistle: '#D8BFD8', + tomato: '#FF6347', + turquoise: '#40E0D0', + violet: '#EE82EE', + wheat: '#F5DEB3', + white: '#FFFFFF', + whitesmoke: '#F5F5F5', + yellow: '#FFFF00', + yellowgreen: '#9ACD32', +} + +export function isDark(color: string = ''): boolean { + color = color.toLowerCase() + // Equation from http://24ways.org/2010/calculating-color-contrast + let rgb = colorMap[color] ? hexToRgb(colorMap[color]) : hexToRgb(color) + const res = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000 + return res < 128 +} diff --git a/lib/defaults.ts b/lib/defaults.ts new file mode 100644 index 00000000..e7422773 --- /dev/null +++ b/lib/defaults.ts @@ -0,0 +1,14 @@ +// Fallback to CMS Data + +export const defaultPageProps = { + header: { + links: [ + { + link: { + title: 'New Arrivals', + url: '/', + }, + }, + ], + }, +} diff --git a/lib/focus-trap.tsx b/lib/focus-trap.tsx new file mode 100644 index 00000000..6e1dc5fe --- /dev/null +++ b/lib/focus-trap.tsx @@ -0,0 +1,64 @@ +import React, { useEffect, RefObject } from 'react' +import { tabbable } from 'tabbable' + +interface Props { + children: React.ReactNode | any + focusFirst?: boolean +} + +export default function FocusTrap({ children, focusFirst = false }: Props) { + const root: RefObject = React.useRef() + const anchor: RefObject = React.useRef(document.activeElement) + + const returnFocus = () => { + // Returns focus to the last focused element prior to trap. + if (anchor) { + anchor.current.focus() + } + } + + const trapFocus = () => { + // Focus the container element + if (root.current) { + root.current.focus() + if (focusFirst) { + selectFirstFocusableEl() + } + } + } + + const selectFirstFocusableEl = () => { + // Try to find focusable elements, if match then focus + // Up to 6 seconds of load time threshold + let match = false + let end = 60 // Try to find match at least n times + let i = 0 + const timer = setInterval(() => { + if (!match !== i > end) { + match = !!tabbable(root.current).length + if (match) { + // Attempt to focus the first el + tabbable(root.current)[0].focus() + } + i = i + 1 + } else { + // Clear interval after n attempts + clearInterval(timer) + } + }, 100) + } + + useEffect(() => { + setTimeout(trapFocus, 20) + return () => { + returnFocus() + } + }, [root, children]) + + return React.createElement('div', { + ref: root, + children, + className: 'outline-none focus-trap', + tabIndex: -1, + }) +} diff --git a/lib/get-slug.ts b/lib/get-slug.ts new file mode 100644 index 00000000..329c5a27 --- /dev/null +++ b/lib/get-slug.ts @@ -0,0 +1,5 @@ +// Remove trailing and leading slash, usually included in nodes +// returned by the BigCommerce API +const getSlug = (path: string) => path.replace(/^\/|\/$/g, '') + +export default getSlug diff --git a/lib/hooks/useAcceptCookies.ts b/lib/hooks/useAcceptCookies.ts new file mode 100644 index 00000000..7f33adf4 --- /dev/null +++ b/lib/hooks/useAcceptCookies.ts @@ -0,0 +1,24 @@ +import Cookies from 'js-cookie' +import { useEffect, useState } from 'react' + +const COOKIE_NAME = 'accept_cookies' + +export const useAcceptCookies = () => { + const [acceptedCookies, setAcceptedCookies] = useState(true) + + useEffect(() => { + if (!Cookies.get(COOKIE_NAME)) { + setAcceptedCookies(false) + } + }, []) + + const acceptCookies = () => { + setAcceptedCookies(true) + Cookies.set(COOKIE_NAME, 'accepted', { expires: 365 }) + } + + return { + acceptedCookies, + onAcceptCookies: acceptCookies, + } +} diff --git a/lib/hooks/useUserAvatar.ts b/lib/hooks/useUserAvatar.ts new file mode 100644 index 00000000..840daae6 --- /dev/null +++ b/lib/hooks/useUserAvatar.ts @@ -0,0 +1,26 @@ +import { useEffect } from 'react' +import { useUI } from '@components/ui/context' +import { getRandomPairOfColors } from '@lib/colors' + +export const useUserAvatar = (name = 'userAvatar') => { + const { userAvatar, setUserAvatar } = useUI() + + useEffect(() => { + if (!userAvatar && localStorage.getItem(name)) { + // Get bg from localStorage and push it to the context. + setUserAvatar(localStorage.getItem(name)) + } + if (!localStorage.getItem(name)) { + // bg not set locally, generating one, setting localStorage and context to persist. + const bg = getRandomPairOfColors() + const value = `linear-gradient(140deg, ${bg[0]}, ${bg[1]} 100%)` + localStorage.setItem(name, value) + setUserAvatar(value) + } + }, []) + + return { + userAvatar, + setUserAvatar, + } +} diff --git a/lib/range-map.ts b/lib/range-map.ts new file mode 100644 index 00000000..886f20d6 --- /dev/null +++ b/lib/range-map.ts @@ -0,0 +1,7 @@ +export default function rangeMap(n: number, fn: (i: number) => any) { + const arr = [] + while (n > arr.length) { + arr.push(fn(arr.length)) + } + return arr +} diff --git a/lib/search.tsx b/lib/search.tsx new file mode 100644 index 00000000..87b42db3 --- /dev/null +++ b/lib/search.tsx @@ -0,0 +1,52 @@ +import { useEffect, useState } from 'react' +import getSlug from './get-slug' + +export function useSearchMeta(asPath: string) { + const [pathname, setPathname] = useState('/search') + const [category, setCategory] = useState() + const [brand, setBrand] = useState() + + useEffect(() => { + // Only access asPath after hydration to avoid a server mismatch + const path = asPath.split('?')[0] + const parts = path.split('/') + + let c = parts[2] + let b = parts[3] + + if (c === 'designers') { + c = parts[4] + } + + setPathname(path) + if (c !== category) setCategory(c) + if (b !== brand) setBrand(b) + }, [asPath]) + + return { pathname, category, brand } +} + +// Removes empty query parameters from the query object +export const filterQuery = (query: any) => + Object.keys(query).reduce((obj, key) => { + if (query[key]?.length) { + obj[key] = query[key] + } + return obj + }, {}) + +export const getCategoryPath = (path: string, brand?: string) => { + const category = getSlug(path) + + return `/search${brand ? `/designers/${brand}` : ''}${ + category ? `/${category}` : '' + }` +} + +export const getDesignerPath = (path: string, category?: string) => { + const designer = getSlug(path).replace(/^brands/, 'designers') + + return `/search${designer ? `/${designer}` : ''}${ + category ? `/${category}` : '' + }` +} diff --git a/lib/to-pixels.ts b/lib/to-pixels.ts new file mode 100644 index 00000000..1701a85f --- /dev/null +++ b/lib/to-pixels.ts @@ -0,0 +1,13 @@ +// Convert numbers or strings to pixel value +// Helpful for styled-jsx when using a prop +// height: ${toPixels(height)}; (supports height={20} and height="20px") + +const toPixels = (value: string | number) => { + if (typeof value === 'number') { + return `${value}px` + } + + return value +} + +export default toPixels diff --git a/lib/usage-warns.ts b/lib/usage-warns.ts new file mode 100644 index 00000000..2033cd02 --- /dev/null +++ b/lib/usage-warns.ts @@ -0,0 +1,26 @@ +/** + * The utils here are used to help developers use the example + */ + +export function missingLocaleInPages(): [string[], () => void] { + const invalidPaths: string[] = [] + const log = () => { + if (invalidPaths.length) { + const single = invalidPaths.length === 1 + const pages = single ? 'page' : 'pages' + + console.log( + `The ${pages} "${invalidPaths.join(', ')}" ${ + single ? 'does' : 'do' + } not include a locale, or the locale is not supported. When using i18n, web pages from +BigCommerce are expected to have a locale or they will be ignored.\n +Please update the ${pages} to include the default locale or make the ${pages} invisible by +unchecking the "Navigation Menu" option in the settings of ${ + single ? 'the' : 'each' + } web page\n` + ) + } + } + + return [invalidPaths, log] +} diff --git a/license.md b/license.md new file mode 100644 index 00000000..fa5d39b6 --- /dev/null +++ b/license.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Vercel, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 00000000..7b7aa2c7 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/next.config.js b/next.config.js new file mode 100644 index 00000000..56037995 --- /dev/null +++ b/next.config.js @@ -0,0 +1,60 @@ +const commerce = require('./commerce.config.json') +const { + withCommerceConfig, + getProviderName, +} = require('./framework/commerce/config') + +const provider = commerce.provider || getProviderName() +const isBC = provider === 'bigcommerce' +const isShopify = provider === 'shopify' +const isSwell = provider === 'swell' +const isVendure = provider === 'vendure' + +module.exports = withCommerceConfig({ + env: { + REACTION_API_DOMAIN: process.env.REACTION_API_DOMAIN, + }, + commerce, + i18n: { + locales: ['en-US', 'es'], + defaultLocale: 'en-US', + }, + rewrites() { + return [ + (isBC || isShopify || isSwell || isVendure) && { + source: '/checkout', + destination: '/api/bigcommerce/checkout', + }, + // The logout is also an action so this route is not required, but it's also another way + // you can allow a logout! + isBC && { + source: '/logout', + destination: '/api/bigcommerce/customers/logout?redirect_to=/', + }, + // For Vendure, rewrite the local api url to the remote (external) api url. This is required + // to make the session cookies work. + isVendure && + process.env.NEXT_PUBLIC_VENDURE_LOCAL_URL && { + source: `${process.env.NEXT_PUBLIC_VENDURE_LOCAL_URL}/:path*`, + destination: `${process.env.NEXT_PUBLIC_VENDURE_SHOP_API_URL}/:path*`, + }, + // Rewrites for /search + { + source: '/search/designers/:name', + destination: '/search', + }, + { + source: '/search/designers/:name/:category', + destination: '/search', + }, + { + // This rewrite will also handle `/search/designers` + source: '/search/:category', + destination: '/search', + }, + ].filter((x) => x) + }, +}) + +// Don't delete this console log, useful to see the commerce config in Vercel deployments +console.log('next.config.js', JSON.stringify(module.exports, null, 2)) diff --git a/package.json b/package.json new file mode 100644 index 00000000..c7e35042 --- /dev/null +++ b/package.json @@ -0,0 +1,124 @@ +{ + "name": "nextjs-commerce", + "version": "1.0.0", + "scripts": { + "dev": "next dev -p 8080", + "build": "next build", + "start": "next start", + "analyze": "BUNDLE_ANALYZE=both yarn build", + "prettier-fix": "prettier --write .", + "find:unused": "next-unused", + "generate": "graphql-codegen", + "generate:reactioncommerce": "graphql-codegen --config framework/reactioncommerce/codegen.json", + "generate:vendure": "graphql-codegen --config framework/vendure/codegen.json", + "generate:definitions": "node framework/bigcommerce/scripts/generate-definitions.js" + }, + "sideEffects": false, + "license": "MIT", + "engines": { + "node": "14.x" + }, + "dependencies": { + "@reach/portal": "^0.11.2", + "@vercel/fetch": "^6.1.0", + "autoprefixer": "^10.2.4", + "body-scroll-lock": "^3.1.5", + "bowser": "^2.11.0", + "classnames": "^2.2.6", + "cookie": "^0.4.1", + "dot-object": "^2.1.4", + "email-validator": "^2.0.4", + "immutability-helper": "^3.1.1", + "js-cookie": "^2.2.1", + "keen-slider": "^5.2.4", + "lodash.debounce": "^4.0.8", + "lodash.random": "^3.2.0", + "lodash.throttle": "^4.1.1", + "next": "^10.0.9-canary.5", + "next-seo": "^4.11.0", + "next-themes": "^0.0.4", + "postcss": "^8.2.8", + "postcss-nesting": "^7.0.1", + "react": "^17.0.1", + "react-dom": "^17.0.1", + "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.4" + }, + "devDependencies": { + "@graphql-codegen/cli": "^1.20.0", + "@graphql-codegen/schema-ast": "^1.18.1", + "@graphql-codegen/typescript": "^1.19.0", + "@graphql-codegen/typescript-operations": "^1.17.13", + "@manifoldco/swagger-to-ts": "^2.1.0", + "@next/bundle-analyzer": "^10.0.1", + "@tailwindcss/jit": "^0.1.3", + "@types/body-scroll-lock": "^2.6.1", + "@types/classnames": "^2.2.10", + "@types/cookie": "^0.4.0", + "@types/js-cookie": "^2.2.6", + "@types/lodash.debounce": "^4.0.6", + "@types/lodash.random": "^3.2.6", + "@types/lodash.throttle": "^4.1.6", + "@types/node": "^14.14.16", + "@types/react": "^17.0.0", + "@types/shopify-buy": "^2.10.5", + "deepmerge": "^4.2.2", + "graphql": "^15.4.0", + "husky": "^4.3.8", + "lint-staged": "^10.5.3", + "next-unused": "^0.0.3", + "postcss-flexbugs-fixes": "^4.2.1", + "postcss-preset-env": "^6.7.0", + "prettier": "^2.2.1", + "typescript": "^4.0.3" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "**/*.{js,jsx,ts,tsx}": [ + "prettier --write", + "git add" + ], + "**/*.{md,mdx,json}": [ + "prettier --write", + "git add" + ] + }, + "next-unused": { + "alias": { + "@lib/*": [ + "lib/*" + ], + "@assets/*": [ + "assets/*" + ], + "@config/*": [ + "config/*" + ], + "@components/*": [ + "components/*" + ], + "@utils/*": [ + "utils/*" + ] + }, + "debug": true, + "include": [ + "components", + "lib", + "pages" + ], + "exclude": [], + "entrypoints": [ + "pages" + ] + } +} diff --git a/pages/[...pages].tsx b/pages/[...pages].tsx new file mode 100644 index 00000000..3f39845b --- /dev/null +++ b/pages/[...pages].tsx @@ -0,0 +1,74 @@ +import type { + GetStaticPathsContext, + GetStaticPropsContext, + InferGetStaticPropsType, +} from 'next' +import { Text } from '@components/ui' +import { Layout } from '@components/common' +import getSlug from '@lib/get-slug' +import { missingLocaleInPages } from '@lib/usage-warns' +import { getConfig } from '@framework/api' +import getPage from '@framework/common/get-page' +import getAllPages from '@framework/common/get-all-pages' +import { defaultPageProps } from '@lib/defaults' + +export async function getStaticProps({ + preview, + params, + locale, +}: GetStaticPropsContext<{ pages: string[] }>) { + const config = getConfig({ locale }) + const { pages } = await getAllPages({ preview, config }) + const path = params?.pages.join('/') + const slug = locale ? `${locale}/${path}` : path + + const pageItem = pages.find((p) => (p.url ? getSlug(p.url) === slug : false)) + const data = + pageItem && + (await getPage({ variables: { id: pageItem.id! }, config, preview })) + const page = data?.page + + if (!page) { + // We throw to make sure this fails at build time as this is never expected to happen + throw new Error(`Page with slug '${slug}' not found`) + } + + return { + props: { ...defaultPageProps, pages, page }, + revalidate: 60 * 60, // Every hour + } +} + +export async function getStaticPaths({ locales }: GetStaticPathsContext) { + const { pages } = await getAllPages() + const [invalidPaths, log] = missingLocaleInPages() + const paths = pages + .map((page) => page.url) + .filter((url) => { + if (!url || !locales) return url + // If there are locales, only include the pages that include one of the available locales + if (locales.includes(getSlug(url).split('/')[0])) return url + + invalidPaths.push(url) + }) + log() + + return { + paths, + // Fallback shouldn't be enabled here or otherwise this route + // will catch every page, even 404s, and we don't want that + fallback: false, + } +} + +export default function Pages({ + page, +}: InferGetStaticPropsType) { + return ( +
    + {page?.body && } +
    + ) +} + +Pages.Layout = Layout diff --git a/pages/_app.tsx b/pages/_app.tsx new file mode 100644 index 00000000..dae0311b --- /dev/null +++ b/pages/_app.tsx @@ -0,0 +1,29 @@ +import '@assets/main.css' +import '@assets/chrome-bug.css' +import 'keen-slider/keen-slider.min.css' + +import { FC, useEffect } from 'react' +import type { AppProps } from 'next/app' +import { Head } from '@components/common' +import { ManagedUIContext } from '@components/ui/context' + +const Noop: FC = ({ children }) => <>{children} + +export default function MyApp({ Component, pageProps }: AppProps) { + const Layout = (Component as any).Layout || Noop + + useEffect(() => { + document.body.classList?.remove('loading') + }, []) + + return ( + <> + + + + + + + + ) +} diff --git a/pages/_document.tsx b/pages/_document.tsx new file mode 100644 index 00000000..dcd214e4 --- /dev/null +++ b/pages/_document.tsx @@ -0,0 +1,17 @@ +import Document, { Head, Html, Main, NextScript } from 'next/document' + +class MyDocument extends Document { + render() { + return ( + + + +
    + + + + ) + } +} + +export default MyDocument diff --git a/pages/api/bigcommerce/cart.ts b/pages/api/bigcommerce/cart.ts new file mode 100644 index 00000000..68ffc3b1 --- /dev/null +++ b/pages/api/bigcommerce/cart.ts @@ -0,0 +1,3 @@ +import cartApi from '@framework/api/cart' + +export default cartApi() diff --git a/pages/api/bigcommerce/catalog/products.ts b/pages/api/bigcommerce/catalog/products.ts new file mode 100644 index 00000000..ac342c82 --- /dev/null +++ b/pages/api/bigcommerce/catalog/products.ts @@ -0,0 +1,3 @@ +import catalogProductsApi from '@framework/api/catalog/products' + +export default catalogProductsApi() diff --git a/pages/api/bigcommerce/checkout.ts b/pages/api/bigcommerce/checkout.ts new file mode 100644 index 00000000..bd754dea --- /dev/null +++ b/pages/api/bigcommerce/checkout.ts @@ -0,0 +1,3 @@ +import checkoutApi from '@framework/api/checkout' + +export default checkoutApi() diff --git a/pages/api/bigcommerce/customers/index.ts b/pages/api/bigcommerce/customers/index.ts new file mode 100644 index 00000000..7b55d3aa --- /dev/null +++ b/pages/api/bigcommerce/customers/index.ts @@ -0,0 +1,3 @@ +import customersApi from '@framework/api/customers' + +export default customersApi() diff --git a/pages/api/bigcommerce/customers/login.ts b/pages/api/bigcommerce/customers/login.ts new file mode 100644 index 00000000..aac52975 --- /dev/null +++ b/pages/api/bigcommerce/customers/login.ts @@ -0,0 +1,3 @@ +import loginApi from '@framework/api/customers/login' + +export default loginApi() diff --git a/pages/api/bigcommerce/customers/logout.ts b/pages/api/bigcommerce/customers/logout.ts new file mode 100644 index 00000000..e872ff95 --- /dev/null +++ b/pages/api/bigcommerce/customers/logout.ts @@ -0,0 +1,3 @@ +import logoutApi from '@framework/api/customers/logout' + +export default logoutApi() diff --git a/pages/api/bigcommerce/customers/signup.ts b/pages/api/bigcommerce/customers/signup.ts new file mode 100644 index 00000000..59f2f840 --- /dev/null +++ b/pages/api/bigcommerce/customers/signup.ts @@ -0,0 +1,3 @@ +import signupApi from '@framework/api/customers/signup' + +export default signupApi() diff --git a/pages/api/bigcommerce/wishlist.ts b/pages/api/bigcommerce/wishlist.ts new file mode 100644 index 00000000..0d6a895a --- /dev/null +++ b/pages/api/bigcommerce/wishlist.ts @@ -0,0 +1,3 @@ +import wishlistApi from '@framework/api/wishlist' + +export default wishlistApi() diff --git a/pages/api/reactioncommerce/cart.ts b/pages/api/reactioncommerce/cart.ts new file mode 100644 index 00000000..68ffc3b1 --- /dev/null +++ b/pages/api/reactioncommerce/cart.ts @@ -0,0 +1,3 @@ +import cartApi from '@framework/api/cart' + +export default cartApi() diff --git a/pages/cart.tsx b/pages/cart.tsx new file mode 100644 index 00000000..cd5bedac --- /dev/null +++ b/pages/cart.tsx @@ -0,0 +1,174 @@ +import type { GetStaticPropsContext } from 'next' +import { getConfig } from '@framework/api' +import getAllPages from '@framework/common/get-all-pages' +import useCart from '@framework/cart/use-cart' +import usePrice from '@framework/product/use-price' +import { Layout } from '@components/common' +import { Button, Text } from '@components/ui' +import { Bag, Cross, Check, MapPin, CreditCard } from '@components/icons' +import { CartItem } from '@components/cart' + +export async function getStaticProps({ + preview, + locale, +}: GetStaticPropsContext) { + const config = getConfig({ locale }) + const { pages } = await getAllPages({ config, preview }) + return { + props: { pages }, + } +} + +export default function Cart() { + const error = null + const success = null + const { data, isLoading, isEmpty } = useCart() + + const { price: subTotal } = usePrice( + data && { + amount: Number(data.subtotalPrice), + currencyCode: data.currency.code, + } + ) + const { price: total } = usePrice( + data && { + amount: Number(data.totalPrice), + currencyCode: data.currency.code, + } + ) + + return ( +
    +
    + {isLoading || isEmpty ? ( +
    + + + +

    + Your cart is empty +

    +

    + Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake. +

    +
    + ) : error ? ( +
    + + + +

    + We couldn’t process the purchase. Please check your card + information and try again. +

    +
    + ) : success ? ( +
    + + + +

    + Thank you for your order. +

    +
    + ) : ( +
    + My Cart + Review your Order +
      + {data!.lineItems.map((item) => ( + + ))} +
    +
    + + Before you leave, take a look at these items. We picked them + just for you + +
    + {[1, 2, 3, 4, 5, 6].map((x) => ( +
    + ))} +
    +
    +
    + )} +
    +
    +
    + {process.env.COMMERCE_CUSTOMCHECKOUT_ENABLED && ( + <> + {/* Shipping Address */} + {/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */} +
    +
    + +
    +
    + + Add Shipping Address + {/* + 1046 Kearny Street.
    + San Franssisco, California +
    */} +
    +
    + {/* Payment Method */} + {/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */} +
    +
    + +
    +
    + + Add Payment Method + {/* VISA #### #### #### 2345 */} +
    +
    + + )} +
    +
      +
    • + Subtotal + {subTotal} +
    • +
    • + Taxes + Calculated at checkout +
    • +
    • + Estimated Shipping + FREE +
    • +
    +
    + Total + {total} +
    +
    +
    +
    + {isEmpty ? ( + + ) : ( + + )} +
    +
    +
    +
    +
    + ) +} + +Cart.Layout = Layout diff --git a/pages/index.tsx b/pages/index.tsx new file mode 100644 index 00000000..e0182da0 --- /dev/null +++ b/pages/index.tsx @@ -0,0 +1,114 @@ +import { Layout } from '@components/common' +import { Grid, Marquee, Hero } from '@components/ui' +import { ProductCard } from '@components/product' +// import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid' +import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next' + +import { getConfig } from '@framework/api' +import getAllProducts from '@framework/product/get-all-products' +import getSiteInfo from '@framework/common/get-site-info' +import getAllPages from '@framework/common/get-all-pages' + +export async function getStaticProps({ + preview, + locale, +}: GetStaticPropsContext) { + const config = getConfig({ locale }) + + const { products } = await getAllProducts({ + variables: { first: 12 }, + config, + preview, + }) + + // const { categories, brands } = await getSiteInfo({ config, preview }) + // const { pages } = await getAllPages({ config, preview }) + + return { + props: { + products, + categories: [], + brands: [], + pages: [], + }, + revalidate: 14400, + } +} + +export default function Home({ + products, + brands, + categories, +}: InferGetStaticPropsType) { + return ( + <> + + {products.slice(0, 3).map((product, i) => ( + + ))} + + + {products.slice(0, 3).map((product, i) => ( + + ))} + + + + {products.slice(0, 3).map((product, i) => ( + + ))} + + + {products.slice(0, 3).map((product, i) => ( + + ))} + + {/* */} + + ) +} + +Home.Layout = Layout diff --git a/pages/orders.tsx b/pages/orders.tsx new file mode 100644 index 00000000..db4ab55b --- /dev/null +++ b/pages/orders.tsx @@ -0,0 +1,38 @@ +import type { GetStaticPropsContext } from 'next' +import { Bag } from '@components/icons' +import { Layout } from '@components/common' +import { Container, Text } from '@components/ui' +import { getConfig } from '@framework/api' +import getAllPages from '@framework/common/get-all-pages' + +export async function getStaticProps({ + preview, + locale, +}: GetStaticPropsContext) { + const config = getConfig({ locale }) + const { pages } = await getAllPages({ config, preview }) + return { + props: { pages }, + } +} + +export default function Orders() { + return ( + + My Orders +
    + + + +

    + No orders found +

    +

    + Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake. +

    +
    +
    + ) +} + +Orders.Layout = Layout diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx new file mode 100644 index 00000000..61420a8d --- /dev/null +++ b/pages/product/[slug].tsx @@ -0,0 +1,70 @@ +import type { + GetStaticPathsContext, + GetStaticPropsContext, + InferGetStaticPropsType, +} from 'next' +import { useRouter } from 'next/router' +import { Layout } from '@components/common' +import { ProductView } from '@components/product' + +import { getConfig } from '@framework/api' +import getProduct from '@framework/product/get-product' +import getAllPages from '@framework/common/get-all-pages' +import getAllProductPaths from '@framework/product/get-all-product-paths' + +export async function getStaticProps({ + params, + locale, + preview, +}: GetStaticPropsContext<{ slug: string }>) { + const config = getConfig({ locale }) + const { pages } = await getAllPages({ config, preview }) + const { product } = await getProduct({ + variables: { slug: params!.slug }, + config, + preview, + }) + + if (!product) { + throw new Error(`Product with slug '${params!.slug}' not found`) + } + + return { + props: { + pages, + product, + }, + revalidate: 200, + } +} + +export async function getStaticPaths({ locales }: GetStaticPathsContext) { + const { products } = await getAllProductPaths() + + return { + paths: locales + ? locales.reduce((arr, locale) => { + // Add a product path for every locale + products.forEach((product) => { + arr.push(`/${locale}/product${product.node.path}`) + }) + return arr + }, []) + : products.map((product) => `/product${product.node.path}`), + fallback: 'blocking', + } +} + +export default function Slug({ + product, +}: InferGetStaticPropsType) { + const router = useRouter() + + return router.isFallback ? ( +

    Loading...

    // TODO (BC) Add Skeleton Views + ) : ( + + ) +} + +Slug.Layout = Layout diff --git a/pages/profile.tsx b/pages/profile.tsx new file mode 100644 index 00000000..ec845c87 --- /dev/null +++ b/pages/profile.tsx @@ -0,0 +1,44 @@ +import type { GetStaticPropsContext } from 'next' +import { getConfig } from '@framework/api' +import getAllPages from '@framework/common/get-all-pages' +import useCustomer from '@framework/customer/use-customer' +import { Layout } from '@components/common' +import { Container, Text } from '@components/ui' + +export async function getStaticProps({ + preview, + locale, +}: GetStaticPropsContext) { + const config = getConfig({ locale }) + const { pages } = await getAllPages({ config, preview }) + return { + props: { pages }, + } +} + +export default function Profile() { + const { data } = useCustomer() + return ( + + My Profile + {data && ( +
    +
    +
    + Full Name + + {data.firstName} {data.lastName} + +
    +
    + Email + {data.email} +
    +
    +
    + )} +
    + ) +} + +Profile.Layout = Layout diff --git a/pages/search.tsx b/pages/search.tsx new file mode 100644 index 00000000..a8ed01ba --- /dev/null +++ b/pages/search.tsx @@ -0,0 +1,473 @@ +import cn from 'classnames' +import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next' +import Link from 'next/link' +import { useState } from 'react' +import { useRouter } from 'next/router' + +import { Layout } from '@components/common' +import { ProductCard } from '@components/product' +import { Container, Grid, Skeleton } from '@components/ui' + +import { getConfig } from '@framework/api' +import useSearch from '@framework/product/use-search' +import getAllPages from '@framework/common/get-all-pages' +import getSiteInfo from '@framework/common/get-site-info' + +import rangeMap from '@lib/range-map' + +// TODO(bc) Remove this. This should come from the API +import getSlug from '@lib/get-slug' + +// TODO (bc) : Remove or standarize this. +const SORT = Object.entries({ + 'latest-desc': 'Latest arrivals', + 'trending-desc': 'Trending', + 'price-asc': 'Price: Low to high', + 'price-desc': 'Price: High to low', +}) + +import { + filterQuery, + getCategoryPath, + getDesignerPath, + useSearchMeta, +} from '@lib/search' +import { Product } from '@commerce/types' + +export async function getStaticProps({ + preview, + locale, +}: GetStaticPropsContext) { + const config = getConfig({ locale }) + const { pages } = await getAllPages({ config, preview }) + const { categories, brands } = await getSiteInfo({ config, preview }) + return { + props: { + pages, + categories, + brands, + shopId: config?.shopId, + }, + } +} + +export default function Search({ + categories, + brands, + shopId, +}: InferGetStaticPropsType) { + const [activeFilter, setActiveFilter] = useState('') + const [toggleFilter, setToggleFilter] = useState(false) + + const router = useRouter() + const { asPath } = router + const { q, sort } = router.query + // `q` can be included but because categories and designers can't be searched + // in the same way of products, it's better to ignore the search input if one + // of those is selected + const query = filterQuery({ sort }) + + const { pathname, category, brand } = useSearchMeta(asPath) + const activeCategory = categories.find( + (cat) => getSlug(cat.path) === category + ) + const activeBrand = brands.find( + (b) => getSlug(b.node.path) === `brands/${brand}` + )?.node + + const { data } = useSearch({ + search: typeof q === 'string' ? q : '', + categoryId: activeCategory?.entityId, + brandId: (activeBrand as any)?.entityId, + sort: typeof sort === 'string' ? sort : '', + shopId, + }) + + const handleClick = (event: any, filter: string) => { + if (filter !== activeFilter) { + setToggleFilter(true) + } else { + setToggleFilter(!toggleFilter) + } + setActiveFilter(filter) + } + + return ( + +
    +
    + {/* Categories */} +
    +
    + + + +
    + +
    + + {/* Designs */} +
    +
    + + + +
    + +
    +
    + {/* Products */} +
    + {(q || activeCategory || activeBrand) && ( +
    + {data ? ( + <> + + Showing {data.products.length} results{' '} + {q && ( + <> + for "{q}" + + )} + + + {q ? ( + <> + There are no products that match "{q}" + + ) : ( + <> + There are no products that match the selected category & + designer + + )} + + + ) : q ? ( + <> + Searching for: "{q}" + + ) : ( + <>Searching... + )} +
    + )} + + {data ? ( + + {data.products.map((product: Product) => ( + + ))} + + ) : ( + + {rangeMap(12, (i) => ( + + ))} + + )} +
    + + {/* Sort */} +
    +
    +
    + + + +
    + +
    +
    +
    +
    + ) +} + +Search.Layout = Layout diff --git a/pages/wishlist.tsx b/pages/wishlist.tsx new file mode 100644 index 00000000..0dddaf23 --- /dev/null +++ b/pages/wishlist.tsx @@ -0,0 +1,68 @@ +import type { GetStaticPropsContext } from 'next' +import { Heart } from '@components/icons' +import { Layout } from '@components/common' +import { Text, Container } from '@components/ui' +import { defaultPageProps } from '@lib/defaults' +import { getConfig } from '@framework/api' +import { useCustomer } from '@framework/customer' +import { WishlistCard } from '@components/wishlist' +import useWishlist from '@framework/wishlist/use-wishlist' +import getAllPages from '@framework/common/get-all-pages' + +export async function getStaticProps({ + preview, + locale, +}: GetStaticPropsContext) { + // Disabling page if Feature is not available + if (!process.env.COMMERCE_WISHLIST_ENABLED) { + return { + notFound: true, + } + } + + const config = getConfig({ locale }) + const { pages } = await getAllPages({ config, preview }) + return { + props: { + pages, + ...defaultPageProps, + }, + } +} + +export default function Wishlist() { + const { data: customer } = useCustomer() + // @ts-ignore Shopify - Fix this types + const { data, isLoading, isEmpty } = useWishlist({ includeProducts: true }) + + return ( + +
    + My Wishlist +
    + {isLoading || isEmpty ? ( +
    + + + +

    + Your wishlist is empty +

    +

    + Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake. +

    +
    + ) : ( + data && + // @ts-ignore Shopify - Fix this types + data.items?.map((item) => ( + + )) + )} +
    +
    +
    + ) +} + +Wishlist.Layout = Layout diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..9e0f0b2c --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,19 @@ +module.exports = { + plugins: [ + 'tailwindcss', + 'postcss-nesting', + 'postcss-flexbugs-fixes', + [ + 'postcss-preset-env', + { + autoprefixer: { + flexbox: 'no-2009', + }, + stage: 3, + features: { + 'custom-properties': false, + }, + }, + ], + ], +} diff --git a/public/bg-products.svg b/public/bg-products.svg new file mode 100644 index 00000000..2118c327 --- /dev/null +++ b/public/bg-products.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/card.png b/public/card.png new file mode 100644 index 00000000..40fcf42d Binary files /dev/null and b/public/card.png differ diff --git a/public/cursor-left.png b/public/cursor-left.png new file mode 100644 index 00000000..3c292b04 Binary files /dev/null and b/public/cursor-left.png differ diff --git a/public/cursor-right.png b/public/cursor-right.png new file mode 100644 index 00000000..e3b46de4 Binary files /dev/null and b/public/cursor-right.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..c4826c94 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/flag-en-us.svg b/public/flag-en-us.svg new file mode 100644 index 00000000..5e77dee3 --- /dev/null +++ b/public/flag-en-us.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/flag-es-ar.svg b/public/flag-es-ar.svg new file mode 100644 index 00000000..4d6ffc47 --- /dev/null +++ b/public/flag-es-ar.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/public/flag-es-co.svg b/public/flag-es-co.svg new file mode 100644 index 00000000..61882039 --- /dev/null +++ b/public/flag-es-co.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/flag-es.svg b/public/flag-es.svg new file mode 100644 index 00000000..5e8e8f08 --- /dev/null +++ b/public/flag-es.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/icon-144x144.png b/public/icon-144x144.png new file mode 100644 index 00000000..aeeaabd3 Binary files /dev/null and b/public/icon-144x144.png differ diff --git a/public/icon-192x192.png b/public/icon-192x192.png new file mode 100644 index 00000000..055ecf31 Binary files /dev/null and b/public/icon-192x192.png differ diff --git a/public/icon-512x512.png b/public/icon-512x512.png new file mode 100644 index 00000000..754628cb Binary files /dev/null and b/public/icon-512x512.png differ diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 00000000..c4df8c7d Binary files /dev/null and b/public/icon.png differ diff --git a/public/jacket.png b/public/jacket.png new file mode 100644 index 00000000..48215364 Binary files /dev/null and b/public/jacket.png differ diff --git a/public/product-img-placeholder.svg b/public/product-img-placeholder.svg new file mode 100644 index 00000000..fbb43bb6 --- /dev/null +++ b/public/product-img-placeholder.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 00000000..bb792da4 --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1,22 @@ +{ + "name": "Next.js Commerce", + "short_name": "Next.js Commerce", + "description": "Next.js Commerce -> https://www.nextjs.org/commerce", + "display": "standalone", + "start_url": "/", + "theme_color": "#fff", + "background_color": "#000000", + "orientation": "portrait", + "icons": [ + { + "src": "/icon-192x192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "/icon-512x512.png", + "type": "image/png", + "sizes": "512x512" + } + ] +} \ No newline at end of file diff --git a/public/slider-arrows.png b/public/slider-arrows.png new file mode 100644 index 00000000..0740919c Binary files /dev/null and b/public/slider-arrows.png differ diff --git a/public/vercel.svg b/public/vercel.svg new file mode 100644 index 00000000..c0a8ee46 --- /dev/null +++ b/public/vercel.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000..1ee8cad1 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,66 @@ +module.exports = { + future: { + purgeLayersByDefault: true, + applyComplexClasses: true, + }, + purge: { + content: [ + './pages/**/*.{js,ts,jsx,tsx}', + './components/**/*.{js,ts,jsx,tsx}', + ], + options: { + safelist: { + standard: ['outline-none'], + }, + }, + }, + theme: { + extend: { + maxWidth: { + '8xl': '1920px', + }, + colors: { + primary: 'var(--primary)', + 'primary-2': 'var(--primary-2)', + secondary: 'var(--secondary)', + 'secondary-2': 'var(--secondary-2)', + hover: 'var(--hover)', + 'hover-1': 'var(--hover-1)', + 'hover-2': 'var(--hover-2)', + 'accents-0': 'var(--accents-0)', + 'accents-1': 'var(--accents-1)', + 'accents-2': 'var(--accents-2)', + 'accents-3': 'var(--accents-3)', + 'accents-4': 'var(--accents-4)', + 'accents-5': 'var(--accents-5)', + 'accents-6': 'var(--accents-6)', + 'accents-7': 'var(--accents-7)', + 'accents-8': 'var(--accents-8)', + 'accents-9': 'var(--accents-9)', + violet: 'var(--violet)', + 'violet-light': 'var(--violet-light)', + pink: 'var(--pink)', + cyan: 'var(--cyan)', + blue: 'var(--blue)', + green: 'var(--green)', + red: 'var(--red)', + }, + textColor: { + base: 'var(--text-base)', + primary: 'var(--text-primary)', + secondary: 'var(--text-secondary)', + }, + boxShadow: { + 'outline-normal': '0 0 0 2px var(--accents-2)', + magical: + 'rgba(0, 0, 0, 0.02) 0px 30px 30px, rgba(0, 0, 0, 0.03) 0px 0px 8px, rgba(0, 0, 0, 0.05) 0px 1px 0px', + }, + lineHeight: { + 'extra-loose': '2.2', + }, + scale: { + 120: '1.2', + }, + }, + }, +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..2f2e7396 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "target": "esnext", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "paths": { + "@lib/*": ["lib/*"], + "@utils/*": ["utils/*"], + "@config/*": ["config/*"], + "@assets/*": ["assets/*"], + "@components/*": ["components/*"], + "@commerce": ["framework/commerce"], + "@commerce/*": ["framework/commerce/*"], + "@framework": ["framework/reactioncommerce"], + "@framework/*": ["framework/reactioncommerce/*"] + } + }, + "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], + "exclude": ["node_modules"] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..da7c7f55 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,7084 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ardatan/aggregate-error@0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@ardatan/aggregate-error/-/aggregate-error-0.0.6.tgz#fe6924771ea40fc98dc7a7045c2e872dc8527609" + integrity sha512-vyrkEHG1jrukmzTPtyWB4NLPauUw5bQeg4uhn8f+1SSynmrOcyvlb1GKQjjgoBzElLdfXCRYX8UnBlhklOHYRQ== + dependencies: + tslib "~2.0.1" + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" + integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== + dependencies: + "@babel/highlight" "^7.12.13" + +"@babel/compat-data@^7.13.15", "@babel/compat-data@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" + integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== + +"@babel/core@^7.0.0": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.3.tgz#5395e30405f0776067fbd9cf0884f15bfb770a38" + integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/generator" "^7.14.3" + "@babel/helper-compilation-targets" "^7.13.16" + "@babel/helper-module-transforms" "^7.14.2" + "@babel/helpers" "^7.14.0" + "@babel/parser" "^7.14.3" + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.14.2" + "@babel/types" "^7.14.2" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.12.13", "@babel/generator@^7.14.2", "@babel/generator@^7.14.3", "@babel/generator@^7.5.0": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.3.tgz#0c2652d91f7bddab7cccc6ba8157e4f40dcedb91" + integrity sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA== + dependencies: + "@babel/types" "^7.14.2" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab" + integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-compilation-targets@^7.13.16": + version "7.13.16" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" + integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== + dependencies: + "@babel/compat-data" "^7.13.15" + "@babel/helper-validator-option" "^7.12.17" + browserslist "^4.14.5" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.13.0": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.3.tgz#832111bcf4f57ca57a4c5b1a000fc125abc6554a" + integrity sha512-BnEfi5+6J2Lte9LeiL6TxLWdIlEv9Woacc1qXzXBgbikcOzMRM2Oya5XGg/f/ngotv1ej2A/b+3iJH8wbS1+lQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-function-name" "^7.14.2" + "@babel/helper-member-expression-to-functions" "^7.13.12" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/helper-replace-supers" "^7.14.3" + "@babel/helper-split-export-declaration" "^7.12.13" + +"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz#397688b590760b6ef7725b5f0860c82427ebaac2" + integrity sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ== + dependencies: + "@babel/helper-get-function-arity" "^7.12.13" + "@babel/template" "^7.12.13" + "@babel/types" "^7.14.2" + +"@babel/helper-get-function-arity@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" + integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-member-expression-to-functions@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" + integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-module-imports@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" + integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-module-transforms@^7.14.0", "@babel/helper-module-transforms@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz#ac1cc30ee47b945e3e0c4db12fa0c5389509dfe5" + integrity sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA== + dependencies: + "@babel/helper-module-imports" "^7.13.12" + "@babel/helper-replace-supers" "^7.13.12" + "@babel/helper-simple-access" "^7.13.12" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-validator-identifier" "^7.14.0" + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.14.2" + "@babel/types" "^7.14.2" + +"@babel/helper-optimise-call-expression@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" + integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" + integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== + +"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.12", "@babel/helper-replace-supers@^7.14.3": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.3.tgz#ca17b318b859d107f0e9b722d58cf12d94436600" + integrity sha512-Rlh8qEWZSTfdz+tgNV/N4gz1a0TMNwCUcENhMjHTHKp3LseYH5Jha0NSlyTQWMnjbYcwFt+bqAMqSLHVXkQ6UA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.13.12" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/traverse" "^7.14.2" + "@babel/types" "^7.14.2" + +"@babel/helper-simple-access@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" + integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-skip-transparent-expression-wrappers@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" + integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-split-export-declaration@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" + integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" + integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== + +"@babel/helper-validator-option@^7.12.17": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" + integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== + +"@babel/helpers@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" + integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== + dependencies: + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" + integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.0" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@7.12.16": + version "7.12.16" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.16.tgz#cc31257419d2c3189d394081635703f549fc1ed4" + integrity sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw== + +"@babel/parser@^7.0.0", "@babel/parser@^7.12.13", "@babel/parser@^7.14.2", "@babel/parser@^7.14.3": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.3.tgz#9b530eecb071fd0c93519df25c5ff9f14759f298" + integrity sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ== + +"@babel/plugin-proposal-class-properties@^7.0.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" + integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.13.0" + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-proposal-object-rest-spread@^7.0.0": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.2.tgz#e17d418f81cc103fedd4ce037e181c8056225abc" + integrity sha512-hBIQFxwZi8GIp934+nj5uV31mqclC1aYDhctDu5khTi9PCCUOczyy0b34W0oE9U/eJXiqQaKyVsmjeagOaSlbw== + dependencies: + "@babel/compat-data" "^7.14.0" + "@babel/helper-compilation-targets" "^7.13.16" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.14.2" + +"@babel/plugin-syntax-class-properties@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.13.tgz#5df9962503c0a9c918381c929d51d4d6949e7e86" + integrity sha512-J/RYxnlSLXZLVR7wTRsozxKT8qbsx1mNKJzXEEjQ0Kjx1ZACcyHgbanNWNCFtc36IzuWhYWPpvJFFoexoOWFmA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz#044fb81ebad6698fe62c478875575bcbb9b70f15" + integrity sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-transform-arrow-functions@^7.0.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" + integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-block-scoped-functions@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4" + integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-transform-block-scoping@^7.0.0": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.2.tgz#761cb12ab5a88d640ad4af4aa81f820e6b5fdf5c" + integrity sha512-neZZcP19NugZZqNwMTH+KoBjx5WyvESPSIOQb4JHpfd+zPfqcH65RMu5xJju5+6q/Y2VzYrleQTr+b6METyyxg== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-classes@^7.0.0": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.2.tgz#3f1196c5709f064c252ad056207d87b7aeb2d03d" + integrity sha512-7oafAVcucHquA/VZCsXv/gmuiHeYd64UJyyTYU+MPfNu0KeNlxw06IeENBO8bJjXVbolu+j1MM5aKQtH1OMCNg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-function-name" "^7.14.2" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-replace-supers" "^7.13.12" + "@babel/helper-split-export-declaration" "^7.12.13" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.0.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed" + integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-destructuring@^7.0.0": + version "7.13.17" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz#678d96576638c19d5b36b332504d3fd6e06dea27" + integrity sha512-UAUqiLv+uRLO+xuBKKMEpC+t7YRNVRqBsWWq1yKXbBZBje/t3IXCiSinZhjn/DC3qzBfICeYd2EFGEbHsh5RLA== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-flow-strip-types@^7.0.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.13.0.tgz#58177a48c209971e8234e99906cb6bd1122addd3" + integrity sha512-EXAGFMJgSX8gxWD7PZtW/P6M+z74jpx3wm/+9pn+c2dOawPpBkUX7BrfyPvo6ZpXbgRIEuwgwDb/MGlKvu2pOg== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-flow" "^7.12.13" + +"@babel/plugin-transform-for-of@^7.0.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062" + integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-function-name@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051" + integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ== + dependencies: + "@babel/helper-function-name" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-transform-literals@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9" + integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-transform-member-expression-literals@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40" + integrity sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-transform-modules-commonjs@^7.0.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" + integrity sha512-EX4QePlsTaRZQmw9BsoPeyh5OCtRGIhwfLquhxGp5e32w+dyL8htOcDwamlitmNFK6xBZYlygjdye9dbd9rUlQ== + dependencies: + "@babel/helper-module-transforms" "^7.14.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-simple-access" "^7.13.12" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-object-super@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7" + integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-replace-supers" "^7.12.13" + +"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.2.tgz#e4290f72e0e9e831000d066427c4667098decc31" + integrity sha512-NxoVmA3APNCC1JdMXkdYXuQS+EMdqy0vIwyDHeKHiJKRxmp1qGSdb0JLEIoPRhkx6H/8Qi3RJ3uqOCYw8giy9A== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-property-literals@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81" + integrity sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-transform-react-display-name@^7.0.0": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.14.2.tgz#2e854544d42ab3bb9c21f84e153d62e800fbd593" + integrity sha512-zCubvP+jjahpnFJvPaHPiGVfuVUjXHhFvJKQdNnsmSsiU9kR/rCZ41jHc++tERD2zV+p7Hr6is+t5b6iWTCqSw== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-react-jsx@^7.0.0": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.14.3.tgz#0e26597805cf0862da735f264550933c38babb66" + integrity sha512-uuxuoUNVhdgYzERiHHFkE4dWoJx+UFVyuAl0aqN8P2/AKFHwqgUC5w2+4/PjpKXJsFgBlYAFXlUmDQ3k3DUkXw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-module-imports" "^7.13.12" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/types" "^7.14.2" + +"@babel/plugin-transform-shorthand-properties@^7.0.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad" + integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-transform-spread@^7.0.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd" + integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + +"@babel/plugin-transform-template-literals@^7.0.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d" + integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/runtime@7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== + 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", "@babel/runtime@^7.12.13", "@babel/runtime@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" + integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== + 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" + integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/parser" "^7.12.13" + "@babel/types" "^7.12.13" + +"@babel/traverse@7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.13.tgz#689f0e4b4c08587ad26622832632735fb8c4e0c0" + integrity sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/generator" "^7.12.13" + "@babel/helper-function-name" "^7.12.13" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/parser" "^7.12.13" + "@babel/types" "^7.12.13" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.2.tgz#9201a8d912723a831c2679c7ebbf2fe1416d765b" + integrity sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/generator" "^7.14.2" + "@babel/helper-function-name" "^7.14.2" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/parser" "^7.14.2" + "@babel/types" "^7.14.2" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.13.tgz#8be1aa8f2c876da11a9cf650c0ecf656913ad611" + integrity sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@babel/types@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" + integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.12", "@babel/types@^7.14.0", "@babel/types@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.2.tgz#4208ae003107ef8a057ea8333e56eb64d2f6a2c3" + integrity sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw== + dependencies: + "@babel/helper-validator-identifier" "^7.14.0" + to-fast-properties "^2.0.0" + +"@csstools/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== + +"@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" + integrity sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA== + dependencies: + lodash.get "^4" + make-error "^1" + ts-node "^9" + tslib "^2" + +"@fullhuman/postcss-purgecss@^3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@fullhuman/postcss-purgecss/-/postcss-purgecss-3.1.3.tgz#47af7b87c9bfb3de4bc94a38f875b928fffdf339" + integrity sha512-kwOXw8fZ0Lt1QmeOOrd+o4Ibvp4UTEBFQbzvWldjlKv5n+G9sXfIPn1hh63IQIL8K8vbvv1oYMJiIUbuy9bGaA== + dependencies: + purgecss "^3.1.3" + +"@graphql-codegen/cli@^1.20.0": + version "1.21.5" + resolved "https://registry.yarnpkg.com/@graphql-codegen/cli/-/cli-1.21.5.tgz#b9041553747cfb2dee7c3473a2e2461ec3e7ada5" + integrity sha512-w3SovNJ9qtMhFLAdPZeCdGvHXDgfdb53mueWDTyncOt04m+tohVnY4qExvyKLTN5zlGxrA/5ubp2x8Az0xQarA== + dependencies: + "@graphql-codegen/core" "1.17.10" + "@graphql-codegen/plugin-helpers" "^1.18.7" + "@graphql-tools/apollo-engine-loader" "^6.2.5" + "@graphql-tools/code-file-loader" "^6.3.1" + "@graphql-tools/git-loader" "^6.2.6" + "@graphql-tools/github-loader" "^6.2.5" + "@graphql-tools/graphql-file-loader" "^6.2.7" + "@graphql-tools/json-file-loader" "^6.2.6" + "@graphql-tools/load" "^6.2.8" + "@graphql-tools/prisma-loader" "^6.3.0" + "@graphql-tools/url-loader" "^6.10.1" + "@graphql-tools/utils" "^7.9.1" + ansi-escapes "^4.3.1" + chalk "^4.1.0" + change-case-all "1.0.14" + chokidar "^3.5.1" + common-tags "^1.8.0" + cosmiconfig "^7.0.0" + debounce "^1.2.0" + dependency-graph "^0.11.0" + detect-indent "^6.0.0" + glob "^7.1.6" + graphql-config "^3.3.0" + inquirer "^7.3.3" + is-glob "^4.0.1" + json-to-pretty-yaml "^1.2.2" + latest-version "5.1.0" + listr "^0.14.3" + listr-update-renderer "^0.5.0" + log-symbols "^4.0.0" + minimatch "^3.0.4" + mkdirp "^1.0.4" + string-env-interpolation "^1.0.1" + ts-log "^2.2.3" + tslib "~2.2.0" + valid-url "^1.0.9" + wrap-ansi "^7.0.0" + yaml "^1.10.0" + yargs "^17.0.0" + +"@graphql-codegen/core@1.17.10": + version "1.17.10" + resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-1.17.10.tgz#3b85b5bc2e84fcacbd25fced5af47a4bb2d7a8bd" + integrity sha512-RA3umgVDs/RI/+ztHh+H4GfJxrJUfWJQqoAkMfX4qPTVO5qsy3R4vPudE0oP8w+kFbL8dFsRfAAPUZxI4jV/hQ== + dependencies: + "@graphql-codegen/plugin-helpers" "^1.18.7" + "@graphql-tools/merge" "^6.2.14" + "@graphql-tools/utils" "^7.9.1" + tslib "~2.2.0" + +"@graphql-codegen/plugin-helpers@^1.18.7": + version "1.18.7" + resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-1.18.7.tgz#465af3e5b02de89e49ddc76ad2546b880fe240f2" + integrity sha512-8ICOrXlsvyL1dpVz8C9b7H31d4DJpDd75WfjMn6Xjqz81Ah8xDn1Bi+7YXRCCILCBmvI94k6fi8qpsIVhFBBjQ== + dependencies: + "@graphql-tools/utils" "^7.9.1" + common-tags "1.8.0" + import-from "3.0.0" + lodash "~4.17.0" + tslib "~2.2.0" + +"@graphql-codegen/schema-ast@^1.18.1": + version "1.18.3" + resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-1.18.3.tgz#7ba7422df716ff2038b1281c503e5751a8414ef2" + integrity sha512-D0uheH039ztSG3mboW5enmyaFwTcevLSR8yNrdN+NEKoQJJoDWsb9P/G6NTdFu5Bb03IvNhIFTpG1ttWtRP/aQ== + dependencies: + "@graphql-codegen/plugin-helpers" "^1.18.7" + "@graphql-tools/utils" "^7.9.1" + tslib "~2.2.0" + +"@graphql-codegen/typescript-operations@^1.17.13": + version "1.18.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-1.18.0.tgz#04c007df476948ff972daed69c73a77a922c8968" + integrity sha512-Q4b+jySBgU39uYzSWQcHBn/q5j/gs2yUQGNiCXhV8IIHDJJNR0Zfb2ywY6AMwT7N3rgXmFuIzKAA++xBf2yKRw== + dependencies: + "@graphql-codegen/plugin-helpers" "^1.18.7" + "@graphql-codegen/typescript" "^1.22.1" + "@graphql-codegen/visitor-plugin-common" "1.21.0" + auto-bind "~4.0.0" + tslib "~2.2.0" + +"@graphql-codegen/typescript@^1.19.0", "@graphql-codegen/typescript@^1.22.1": + version "1.22.1" + resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript/-/typescript-1.22.1.tgz#9a2e215d4cf095d942c1671db4bad78b619b11ce" + integrity sha512-3f/siciXrhhMdcs9qcxnwWXETsAhZNNiUOlr6IUEm82kVx5xvFuxc0KZZE88w3iEVJXE7xYo1oWmrttvkQP4Aw== + dependencies: + "@graphql-codegen/plugin-helpers" "^1.18.7" + "@graphql-codegen/visitor-plugin-common" "1.21.0" + auto-bind "~4.0.0" + tslib "~2.2.0" + +"@graphql-codegen/visitor-plugin-common@1.21.0": + version "1.21.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-1.21.0.tgz#1cb59a8ce9a9d6486f859a254645e162c6736cfb" + integrity sha512-gw6mUCOpKwJ4aR+wnUXureQi4dV6jezEiXvX0CEZdpqBIGAJ4G8h7CKyGW66lBzvaoLCB7siOF86UJO3dw5ctg== + dependencies: + "@graphql-codegen/plugin-helpers" "^1.18.7" + "@graphql-tools/optimize" "^1.0.1" + "@graphql-tools/relay-operation-optimizer" "^6.3.0" + array.prototype.flatmap "^1.2.4" + auto-bind "~4.0.0" + change-case-all "1.0.14" + dependency-graph "^0.11.0" + graphql-tag "^2.11.0" + parse-filepath "^1.0.2" + tslib "~2.2.0" + +"@graphql-tools/apollo-engine-loader@^6.2.5": + version "6.2.5" + resolved "https://registry.yarnpkg.com/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-6.2.5.tgz#b9e65744f522bb9f6ca50651e5622820c4f059a8" + integrity sha512-CE4uef6PyxtSG+7OnLklIr2BZZDgjO89ZXK47EKdY7jQy/BQD/9o+8SxPsgiBc+2NsDJH2I6P/nqoaJMOEat6g== + dependencies: + "@graphql-tools/utils" "^7.0.0" + cross-fetch "3.0.6" + tslib "~2.0.1" + +"@graphql-tools/batch-execute@^7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-7.1.2.tgz#35ba09a1e0f80f34f1ce111d23c40f039d4403a0" + integrity sha512-IuR2SB2MnC2ztA/XeTMTfWcA0Wy7ZH5u+nDkDNLAdX+AaSyDnsQS35sCmHqG0VOGTl7rzoyBWLCKGwSJplgtwg== + dependencies: + "@graphql-tools/utils" "^7.7.0" + dataloader "2.0.0" + tslib "~2.2.0" + value-or-promise "1.0.6" + +"@graphql-tools/code-file-loader@^6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-6.3.1.tgz#42dfd4db5b968acdb453382f172ec684fa0c34ed" + integrity sha512-ZJimcm2ig+avgsEOWWVvAaxZrXXhiiSZyYYOJi0hk9wh5BxZcLUNKkTp6EFnZE/jmGUwuos3pIjUD3Hwi3Bwhg== + dependencies: + "@graphql-tools/graphql-tag-pluck" "^6.5.1" + "@graphql-tools/utils" "^7.0.0" + tslib "~2.1.0" + +"@graphql-tools/delegate@^7.0.1", "@graphql-tools/delegate@^7.1.5": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-7.1.5.tgz#0b027819b7047eff29bacbd5032e34a3d64bd093" + integrity sha512-bQu+hDd37e+FZ0CQGEEczmRSfQRnnXeUxI/0miDV+NV/zCbEdIJj5tYFNrKT03W6wgdqx8U06d8L23LxvGri/g== + dependencies: + "@ardatan/aggregate-error" "0.0.6" + "@graphql-tools/batch-execute" "^7.1.2" + "@graphql-tools/schema" "^7.1.5" + "@graphql-tools/utils" "^7.7.1" + dataloader "2.0.0" + tslib "~2.2.0" + value-or-promise "1.0.6" + +"@graphql-tools/git-loader@^6.2.6": + version "6.2.6" + resolved "https://registry.yarnpkg.com/@graphql-tools/git-loader/-/git-loader-6.2.6.tgz#c2226f4b8f51f1c05c9ab2649ba32d49c68cd077" + integrity sha512-ooQTt2CaG47vEYPP3CPD+nbA0F+FYQXfzrB1Y1ABN9K3d3O2RK3g8qwslzZaI8VJQthvKwt0A95ZeE4XxteYfw== + dependencies: + "@graphql-tools/graphql-tag-pluck" "^6.2.6" + "@graphql-tools/utils" "^7.0.0" + tslib "~2.1.0" + +"@graphql-tools/github-loader@^6.2.5": + version "6.2.5" + resolved "https://registry.yarnpkg.com/@graphql-tools/github-loader/-/github-loader-6.2.5.tgz#460dff6f5bbaa26957a5ea3be4f452b89cc6a44b" + integrity sha512-DLuQmYeNNdPo8oWus8EePxWCfCAyUXPZ/p1PWqjrX/NGPyH2ZObdqtDAfRHztljt0F/qkBHbGHCEk2TKbRZTRw== + dependencies: + "@graphql-tools/graphql-tag-pluck" "^6.2.6" + "@graphql-tools/utils" "^7.0.0" + cross-fetch "3.0.6" + tslib "~2.0.1" + +"@graphql-tools/graphql-file-loader@^6.0.0", "@graphql-tools/graphql-file-loader@^6.2.7": + version "6.2.7" + resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-6.2.7.tgz#d3720f2c4f4bb90eb2a03a7869a780c61945e143" + integrity sha512-5k2SNz0W87tDcymhEMZMkd6/vs6QawDyjQXWtqkuLTBF3vxjxPD1I4dwHoxgWPIjjANhXybvulD7E+St/7s9TQ== + dependencies: + "@graphql-tools/import" "^6.2.6" + "@graphql-tools/utils" "^7.0.0" + tslib "~2.1.0" + +"@graphql-tools/graphql-tag-pluck@^6.2.6", "@graphql-tools/graphql-tag-pluck@^6.5.1": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-6.5.1.tgz#5fb227dbb1e19f4b037792b50f646f16a2d4c686" + integrity sha512-7qkm82iFmcpb8M6/yRgzjShtW6Qu2OlCSZp8uatA3J0eMl87TxyJoUmL3M3UMMOSundAK8GmoyNVFUrueueV5Q== + dependencies: + "@babel/parser" "7.12.16" + "@babel/traverse" "7.12.13" + "@babel/types" "7.12.13" + "@graphql-tools/utils" "^7.0.0" + tslib "~2.1.0" + +"@graphql-tools/import@^6.2.6": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/import/-/import-6.3.1.tgz#731c47ab6c6ac9f7994d75c76b6c2fa127d2d483" + integrity sha512-1szR19JI6WPibjYurMLdadHKZoG9C//8I/FZ0Dt4vJSbrMdVNp8WFxg4QnZrDeMG4MzZc90etsyF5ofKjcC+jw== + dependencies: + resolve-from "5.0.0" + tslib "~2.2.0" + +"@graphql-tools/json-file-loader@^6.0.0", "@graphql-tools/json-file-loader@^6.2.6": + version "6.2.6" + resolved "https://registry.yarnpkg.com/@graphql-tools/json-file-loader/-/json-file-loader-6.2.6.tgz#830482cfd3721a0799cbf2fe5b09959d9332739a" + integrity sha512-CnfwBSY5926zyb6fkDBHnlTblHnHI4hoBALFYXnrg0Ev4yWU8B04DZl/pBRUc459VNgO2x8/mxGIZj2hPJG1EA== + dependencies: + "@graphql-tools/utils" "^7.0.0" + tslib "~2.0.1" + +"@graphql-tools/load@^6.0.0", "@graphql-tools/load@^6.2.8": + version "6.2.8" + resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-6.2.8.tgz#16900fb6e75e1d075cad8f7ea439b334feb0b96a" + integrity sha512-JpbyXOXd8fJXdBh2ta0Q4w8ia6uK5FHzrTNmcvYBvflFuWly2LDTk2abbSl81zKkzswQMEd2UIYghXELRg8eTA== + dependencies: + "@graphql-tools/merge" "^6.2.12" + "@graphql-tools/utils" "^7.5.0" + globby "11.0.3" + import-from "3.0.0" + is-glob "4.0.1" + p-limit "3.1.0" + tslib "~2.2.0" + unixify "1.0.0" + valid-url "1.0.9" + +"@graphql-tools/merge@^6.0.0", "@graphql-tools/merge@^6.2.12", "@graphql-tools/merge@^6.2.14": + version "6.2.14" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-6.2.14.tgz#694e2a2785ba47558e5665687feddd2935e9d94e" + integrity sha512-RWT4Td0ROJai2eR66NHejgf8UwnXJqZxXgDWDI+7hua5vNA2OW8Mf9K1Wav1ZkjWnuRp4ztNtkZGie5ISw55ow== + dependencies: + "@graphql-tools/schema" "^7.0.0" + "@graphql-tools/utils" "^7.7.0" + tslib "~2.2.0" + +"@graphql-tools/optimize@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-1.0.1.tgz#9933fffc5a3c63f95102b1cb6076fb16ac7bb22d" + integrity sha512-cRlUNsbErYoBtzzS6zXahXeTBZGPVlPHXCpnEZ0XiK/KY/sQL96cyzak0fM/Gk6qEI9/l32MYEICjasiBQrl5w== + dependencies: + tslib "~2.0.1" + +"@graphql-tools/prisma-loader@^6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/prisma-loader/-/prisma-loader-6.3.0.tgz#c907e17751ff2b26e7c2bc75d0913ebf03f970da" + integrity sha512-9V3W/kzsFBmUQqOsd96V4a4k7Didz66yh/IK89B1/rrvy9rYj+ULjEqR73x9BYZ+ww9FV8yP8LasWAJwWaqqJQ== + dependencies: + "@graphql-tools/url-loader" "^6.8.2" + "@graphql-tools/utils" "^7.0.0" + "@types/http-proxy-agent" "^2.0.2" + "@types/js-yaml" "^4.0.0" + "@types/json-stable-stringify" "^1.0.32" + "@types/jsonwebtoken" "^8.5.0" + chalk "^4.1.0" + debug "^4.3.1" + dotenv "^8.2.0" + graphql-request "^3.3.0" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + isomorphic-fetch "^3.0.0" + js-yaml "^4.0.0" + json-stable-stringify "^1.0.1" + jsonwebtoken "^8.5.1" + lodash "^4.17.20" + replaceall "^0.1.6" + scuid "^1.1.0" + tslib "~2.1.0" + yaml-ast-parser "^0.0.43" + +"@graphql-tools/relay-operation-optimizer@^6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.3.0.tgz#f8c7f6c8aa4a9cf50ab151fbc5db4f4282a79532" + integrity sha512-Or3UgRvkY9Fq1AAx7q38oPqFmTepLz7kp6wDHKyR0ceG7AvHv5En22R12mAeISInbhff4Rpwgf6cE8zHRu6bCw== + dependencies: + "@graphql-tools/utils" "^7.1.0" + relay-compiler "10.1.0" + tslib "~2.0.1" + +"@graphql-tools/schema@^7.0.0", "@graphql-tools/schema@^7.1.5": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-7.1.5.tgz#07b24e52b182e736a6b77c829fc48b84d89aa711" + integrity sha512-uyn3HSNSckf4mvQSq0Q07CPaVZMNFCYEVxroApOaw802m9DcZPgf9XVPy/gda5GWj9AhbijfRYVTZQgHnJ4CXA== + dependencies: + "@graphql-tools/utils" "^7.1.2" + tslib "~2.2.0" + value-or-promise "1.0.6" + +"@graphql-tools/url-loader@^6.0.0", "@graphql-tools/url-loader@^6.10.1", "@graphql-tools/url-loader@^6.8.2": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/url-loader/-/url-loader-6.10.1.tgz#dc741e4299e0e7ddf435eba50a1f713b3e763b33" + integrity sha512-DSDrbhQIv7fheQ60pfDpGD256ixUQIR6Hhf9Z5bRjVkXOCvO5XrkwoWLiU7iHL81GB1r0Ba31bf+sl+D4nyyfw== + dependencies: + "@graphql-tools/delegate" "^7.0.1" + "@graphql-tools/utils" "^7.9.0" + "@graphql-tools/wrap" "^7.0.4" + "@microsoft/fetch-event-source" "2.0.1" + "@types/websocket" "1.0.2" + abort-controller "3.0.0" + cross-fetch "3.1.4" + extract-files "9.0.0" + form-data "4.0.0" + graphql-ws "^4.4.1" + is-promise "4.0.0" + isomorphic-ws "4.0.1" + lodash "4.17.21" + meros "1.1.4" + subscriptions-transport-ws "^0.9.18" + sync-fetch "0.3.0" + tslib "~2.2.0" + valid-url "1.0.9" + ws "7.4.5" + +"@graphql-tools/utils@^7.0.0", "@graphql-tools/utils@^7.1.0", "@graphql-tools/utils@^7.1.2", "@graphql-tools/utils@^7.5.0", "@graphql-tools/utils@^7.7.0", "@graphql-tools/utils@^7.7.1", "@graphql-tools/utils@^7.8.1", "@graphql-tools/utils@^7.9.0", "@graphql-tools/utils@^7.9.1": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.10.0.tgz#07a4cb5d1bec1ff1dc1d47a935919ee6abd38699" + integrity sha512-d334r6bo9mxdSqZW6zWboEnnOOFRrAPVQJ7LkU8/6grglrbcu6WhwCLzHb90E94JI3TD3ricC3YGbUqIi9Xg0w== + dependencies: + "@ardatan/aggregate-error" "0.0.6" + camel-case "4.1.2" + tslib "~2.2.0" + +"@graphql-tools/wrap@^7.0.4": + version "7.0.8" + resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-7.0.8.tgz#ad41e487135ca3ea1ae0ea04bb3f596177fb4f50" + integrity sha512-1NDUymworsOlb53Qfh7fonDi2STvqCtbeE68ntKY9K/Ju/be2ZNxrFSbrBHwnxWcN9PjISNnLcAyJ1L5tCUyhg== + dependencies: + "@graphql-tools/delegate" "^7.1.5" + "@graphql-tools/schema" "^7.1.5" + "@graphql-tools/utils" "^7.8.1" + tslib "~2.2.0" + value-or-promise "1.0.6" + +"@hapi/accept@5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@hapi/accept/-/accept-5.0.2.tgz#ab7043b037e68b722f93f376afb05e85c0699523" + integrity sha512-CmzBx/bXUR8451fnZRuZAJRlzgm0Jgu5dltTX/bszmR2lheb9BpyN47Q1RbaGTsvFzn0PXAEs+lXDKfshccYZw== + dependencies: + "@hapi/boom" "9.x.x" + "@hapi/hoek" "9.x.x" + +"@hapi/boom@9.x.x": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.1.2.tgz#48bd41d67437164a2d636e3b5bc954f8c8dc5e38" + integrity sha512-uJEJtiNHzKw80JpngDGBCGAmWjBtzxDCz17A9NO2zCi8LLBlb5Frpq4pXwyN+2JQMod4pKz5BALwyneCgDg89Q== + dependencies: + "@hapi/hoek" "9.x.x" + +"@hapi/hoek@9.x.x": + version "9.2.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.0.tgz#f3933a44e365864f4dad5db94158106d511e8131" + integrity sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug== + +"@iarna/toml@^2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" + integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== + +"@manifoldco/swagger-to-ts@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@manifoldco/swagger-to-ts/-/swagger-to-ts-2.1.0.tgz#b52a429e5b4ab3627571d3e9ae7399cf5cd4c454" + integrity sha512-IH0FAHhwWHR3Gs3rnVHNEscZujGn+K6/2Zu5cWfZre3Vz2tx1SvvJKEbSM89MztfDDRjOpb+6pQD/vqdEoTBVg== + dependencies: + chalk "^4.0.0" + js-yaml "^3.13.1" + meow "^7.0.0" + prettier "^2.0.5" + +"@microsoft/fetch-event-source@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d" + integrity sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA== + +"@next/bundle-analyzer@^10.0.1": + version "10.2.3" + resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-10.2.3.tgz#6526e31f46cd48145986dc3bf911ff693e2acdf7" + integrity sha512-vEfQhGWgJugZOlSUlj3DZWs/KsK0SO2SPKoHSZ7KkzpruKzc/e45G0oUh0rffzdhasMQZM1TuSBkxO+1UcnDNw== + dependencies: + webpack-bundle-analyzer "4.3.0" + +"@next/env@10.2.3": + version "10.2.3" + resolved "https://registry.yarnpkg.com/@next/env/-/env-10.2.3.tgz#ede3bbe68cec9939c37168ea2077f9adbc68334e" + integrity sha512-uBOjRBjsWC4C8X3DfmWWP6ekwLnf2JCCwQX9KVnJtJkqfDsv1yQPakdOEwvJzXQc3JC/v5KKffYPVmV2wHXCgQ== + +"@next/polyfill-module@10.2.3": + version "10.2.3" + resolved "https://registry.yarnpkg.com/@next/polyfill-module/-/polyfill-module-10.2.3.tgz#5a29f50c3ce3a56b8268d3b8331c691d8039467a" + integrity sha512-OkeY4cLhzfYbXxM4fd+6V4s5pTPuyfKSlavItfNRA6PpS7t1/R6YjO7S7rB8tu1pbTGuDHGIdE1ioDv15bAbDQ== + +"@next/react-dev-overlay@10.2.3": + version "10.2.3" + resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-10.2.3.tgz#95313d10a8848f6c7b9e31ae3bd2a3627d136841" + integrity sha512-E6g2jws4YW94l0lMMopBVKIZK2mEHfSBvM0d9dmzKG9L/A/kEq6LZCB4SiwGJbNsAdlk2y3USDa0oNbpA+m5Kw== + dependencies: + "@babel/code-frame" "7.12.11" + anser "1.4.9" + chalk "4.0.0" + classnames "2.2.6" + css.escape "1.5.1" + data-uri-to-buffer "3.0.1" + platform "1.3.6" + shell-quote "1.7.2" + source-map "0.8.0-beta.0" + stacktrace-parser "0.1.10" + strip-ansi "6.0.0" + +"@next/react-refresh-utils@10.2.3": + version "10.2.3" + resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-10.2.3.tgz#2f3e42fe6680798f276e3621345c2886b231348b" + integrity sha512-qtBF56vPC6d6a8p7LYd0iRjW89fhY80kAIzmj+VonvIGjK/nymBjcFUhbKiMFqlhsarCksnhwX+Zmn95Dw9qvA== + +"@nodelib/fs.scandir@2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" + integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA== + dependencies: + "@nodelib/fs.stat" "2.0.4" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" + integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" + integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow== + dependencies: + "@nodelib/fs.scandir" "2.1.4" + fastq "^1.6.0" + +"@opentelemetry/api@0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-0.14.0.tgz#4e17d8d2f1da72b19374efa7b6526aa001267cae" + integrity sha512-L7RMuZr5LzMmZiQSQDy9O1jo0q+DaLy6XpYJfIGfYSfoJA5qzYwUP3sP1uMIQ549DvxAgM3ng85EaPTM/hUHwQ== + dependencies: + "@opentelemetry/context-base" "^0.14.0" + +"@opentelemetry/context-base@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.14.0.tgz#c67fc20a4d891447ca1a855d7d70fa79a3533001" + integrity sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw== + +"@polka/url@^1.0.0-next.15": + version "1.0.0-next.15" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.15.tgz#6a9d143f7f4f49db2d782f9e1c8839a29b43ae23" + integrity sha512-15spi3V28QdevleWBNXE4pIls3nFZmBbUGrW9IVPwiQczuSb9n76TCB4bsk8TSel+I1OkHEdPhu5QKMfY6rQHA== + +"@reach/portal@^0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@reach/portal/-/portal-0.11.2.tgz#19a671be9ff010a345892b81e710cb6e4d9f9762" + integrity sha512-/53A/rY5oX2Y7D5TpvsP+V5cSd+4MPY6f21mAmVn4DCVwpkCFOlJ059ZL7ixS85M0Jz48YQnnvBJUqwkxqUG/g== + dependencies: + "@reach/utils" "0.11.2" + tslib "^2.0.0" + +"@reach/utils@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.11.2.tgz#be1f03650db56fd67a16d3fc70e5262cdb139cec" + integrity sha512-fBTolYj+rKTROXmf0zHO0rCWSvw7J0ALmYj5QxW4DmITMOH5uyRuWDWOfqohIGFbOtF/sum50WTB3tvx76d+Aw== + dependencies: + "@types/warning" "^3.0.0" + tslib "^2.0.0" + warning "^4.0.3" + +"@samverschueren/stream-to-observable@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz#a21117b19ee9be70c379ec1877537ef2e1c63301" + integrity sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ== + dependencies: + any-observable "^0.3.0" + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@tailwindcss/jit@^0.1.3": + version "0.1.18" + resolved "https://registry.yarnpkg.com/@tailwindcss/jit/-/jit-0.1.18.tgz#f44ac25b347ad1b4056af4fbda69399070206825" + integrity sha512-WNSEiwbggtO9n6+ok2fFdYmhqY20oqLmB82H23nY8P5WzijZbIshojoY3s/OvPD7cmvzkweZ6LLKGWuDS1/vLA== + dependencies: + chokidar "^3.5.1" + dlv "^1.1.3" + fast-glob "^3.2.5" + lodash.topath "^4.5.2" + normalize-path "^3.0.0" + object-hash "^2.1.1" + parse-glob "^3.0.4" + postcss-selector-parser "^6.0.4" + quick-lru "^5.1.1" + +"@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== + +"@types/async-retry@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@types/async-retry/-/async-retry-1.2.1.tgz#fa9ac165907a8ee78f4924f4e393b656c65b5bb4" + integrity sha512-yMQ6CVgICWtyFNBqJT3zqOc+TnqqEPLo4nKJNPFwcialiylil38Ie6q1ENeFTjvaLOkVim9K5LisHgAKJWidGQ== + +"@types/body-scroll-lock@^2.6.1": + version "2.6.1" + resolved "https://registry.yarnpkg.com/@types/body-scroll-lock/-/body-scroll-lock-2.6.1.tgz#0dbd2b6ad2f4cfcece7102d6cf8630ce95508ee0" + integrity sha512-PPFm/2A6LfKmSpvMg58gHtSqwwMChbcKKGhSCRIhY4MyFzhY8moAN6HrTCpOeZQUqkFdTFfMqr7njeqGLKt72Q== + +"@types/classnames@^2.2.10": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.3.1.tgz#3c2467aa0f1a93f1f021e3b9bcf938bd5dfdc0dd" + integrity sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A== + dependencies: + classnames "*" + +"@types/cookie@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.0.tgz#14f854c0f93d326e39da6e3b6f34f7d37513d108" + integrity sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg== + +"@types/http-proxy-agent@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/http-proxy-agent/-/http-proxy-agent-2.0.2.tgz#942c1f35c7e1f0edd1b6ffae5d0f9051cfb32be1" + integrity sha512-2S6IuBRhqUnH1/AUx9k8KWtY3Esg4eqri946MnxTG5HwehF1S5mqLln8fcyMiuQkY72p2gH3W+rIPqp5li0LyQ== + dependencies: + "@types/node" "*" + +"@types/js-cookie@^2.2.6": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.6.tgz#f1a1cb35aff47bc5cfb05cb0c441ca91e914c26f" + integrity sha512-+oY0FDTO2GYKEV0YPvSshGq9t7YozVkgvXLty7zogQNuCxBhT9/3INX9Q7H1aRZ4SUDRXAKlJuA4EA5nTt7SNw== + +"@types/js-yaml@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.1.tgz#5544730b65a480b18ace6b6ce914e519cec2d43b" + integrity sha512-xdOvNmXmrZqqPy3kuCQ+fz6wA0xU5pji9cd1nDrflWaAWtYLLGk5ykW0H6yg5TVyehHP1pfmuuSaZkhP+kspVA== + +"@types/json-stable-stringify@^1.0.32": + version "1.0.32" + resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.0.32.tgz#121f6917c4389db3923640b2e68de5fa64dda88e" + integrity sha512-q9Q6+eUEGwQkv4Sbst3J4PNgDOvpuVuKj79Hl/qnmBMEIPzB5QoFRUtjcgcg2xNUZyYUGXBk5wYIBKHt0A+Mxw== + +"@types/jsonwebtoken@^8.5.0": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#56958cb2d80f6d74352bd2e501a018e2506a8a84" + integrity sha512-rNAPdomlIUX0i0cg2+I+Q1wOUr531zHBQ+cV/28PJ39bSPKjahatZZ2LMuhiguETkCgLVzfruw/ZvNMNkKoSzw== + dependencies: + "@types/node" "*" + +"@types/lodash.debounce@^4.0.6": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz#c5a2326cd3efc46566c47e4c0aa248dc0ee57d60" + integrity sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ== + dependencies: + "@types/lodash" "*" + +"@types/lodash.random@^3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@types/lodash.random/-/lodash.random-3.2.6.tgz#64b08abad168dca39c778ed40cce75b2f9e168eb" + integrity sha512-RRr0pKm+3USvG/HTkuRKA8v2EqXu19VXC09j4VL2UQec8Yx8Fn6wYTPGjYdmX4UFd23ykS7SLFkiULS/rv8kTA== + dependencies: + "@types/lodash" "*" + +"@types/lodash.throttle@^4.1.6": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/lodash.throttle/-/lodash.throttle-4.1.6.tgz#f5ba2c22244ee42ff6c2c49e614401a870c1009c" + integrity sha512-/UIH96i/sIRYGC60NoY72jGkCJtFN5KVPhEMMMTjol65effe1gPn0tycJqV5tlSwMTzX8FqzB5yAj0rfGHTPNg== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.170" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6" + integrity sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q== + +"@types/lru-cache@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-4.1.1.tgz#b2d87a5e3df8d4b18ca426c5105cd701c2306d40" + integrity sha512-8mNEUG6diOrI6pMqOHrHPDBB1JsrpedeMK9AWGzVCQ7StRRribiT9BRvUmF8aUws9iBbVlgVekOT5Sgzc1MTKw== + +"@types/minimist@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" + integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== + +"@types/node-fetch@2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.3.2.tgz#e01893b176c6fa1367743726380d65bce5d6576b" + integrity sha512-yW0EOebSsQme9yKu09XbdDfle4/SmWZMK4dfteWcSLCYNQQcF+YOv0kIrvm+9pO11/ghA4E6A+RNQqvYj4Nr3A== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "15.6.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.6.1.tgz#32d43390d5c62c5b6ec486a9bc9c59544de39a08" + integrity sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA== + +"@types/node@10.12.18": + version "10.12.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== + +"@types/node@^14.14.16": + version "14.17.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.1.tgz#5e07e0cb2ff793aa7a1b41deae76221e6166049f" + integrity sha512-/tpUyFD7meeooTRwl3sYlihx2BrJE7q9XF71EguPFIySj9B7qgnRtHsHTho+0AUm4m1SvWGm6uSncrR94q6Vtw== + +"@types/normalize-package-data@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + +"@types/react@^17.0.0": + version "17.0.8" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.8.tgz#fe76e3ba0fbb5602704110fd1e3035cf394778e3" + integrity sha512-3sx4c0PbXujrYAKwXxNONXUtRp9C+hE2di0IuxFyf5BELD+B+AXL8G7QrmSKhVwKZDbv0igiAjQAMhXj8Yg3aw== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275" + integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA== + +"@types/shopify-buy@^2.10.5": + version "2.10.5" + resolved "https://registry.yarnpkg.com/@types/shopify-buy/-/shopify-buy-2.10.5.tgz#c7184b792989a968af879224e8990cde4db45519" + integrity sha512-12Le/iXPynrONntux/OaXf9+yx0zbMBKhwywdej9mfR8YhXB82pPZYzU3o6j8cjK1uCQ/wWkqLTftpaXpeMKig== + +"@types/warning@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52" + integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI= + +"@types/websocket@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.2.tgz#d2855c6a312b7da73ed16ba6781815bf30c6187a" + integrity sha512-B5m9aq7cbbD/5/jThEr33nUY8WEfVi6A2YKCTOvw5Ldy7mtsOkqRvGjnzy6g7iMMDsgu7xREuCzqATLDLQVKcQ== + dependencies: + "@types/node" "*" + +"@typescript-eslint/typescript-estree@^2.29.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" + integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@vercel/fetch-cached-dns@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@vercel/fetch-cached-dns/-/fetch-cached-dns-2.0.1.tgz#b929ba5b4b6f7108abf49adaf03309159047c134" + integrity sha512-4a2IoekfGUgV/dinAB7Tx5oqA+Pg9I/6x/t8n/yduHmdclP5EdWTN4gPrwOKVECKVn2pV1VxAT8q4toSzwa2Eg== + dependencies: + "@types/node-fetch" "2.3.2" + "@zeit/dns-cached-resolve" "2.1.0" + +"@vercel/fetch-retry@^5.0.2": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@vercel/fetch-retry/-/fetch-retry-5.0.3.tgz#cce5d23f6e64f6f525c24e2ac7c78f65d6c5b1f4" + integrity sha512-DIIoBY92r+sQ6iHSf5WjKiYvkdsDIMPWKYATlE0KcUAj2RV6SZK9UWpUzBRKsofXqedOqpVjrI0IE6AWL7JRtg== + dependencies: + async-retry "^1.3.1" + debug "^3.1.0" + +"@vercel/fetch@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@vercel/fetch/-/fetch-6.1.0.tgz#4959cd264d25e811b46491818a9d9ca5d752a2a9" + integrity sha512-xR0GQggKhPvwEWrqcrobsQFjyR/bDDbX24BkSaRyLzW+8SydKhkBc/mBCUV8h4SBZSlJMJnqhrxjFCZ1uJcqNg== + dependencies: + "@types/async-retry" "1.2.1" + "@vercel/fetch-cached-dns" "^2.0.1" + "@vercel/fetch-retry" "^5.0.2" + agentkeepalive "3.4.1" + debug "3.1.0" + +"@zeit/dns-cached-resolve@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@zeit/dns-cached-resolve/-/dns-cached-resolve-2.1.0.tgz#78583010df1683fdb7b05949b75593c9a8641bc1" + integrity sha512-KD2zyRZEBNs9PJ3/ob7zx0CvR4wM0oV4G5s5gFfPwmM74GpFbUN2pAAivP2AXnUrJ14Nkh8NumNKOzOyc4LbFQ== + dependencies: + "@types/async-retry" "1.2.1" + "@types/lru-cache" "4.1.1" + "@types/node" "10.12.18" + async-retry "1.2.3" + lru-cache "5.1.1" + +abort-controller@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +acorn-node@^1.6.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + +acorn-walk@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn-walk@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.1.0.tgz#d3c6a9faf00987a5e2b9bdb506c2aa76cd707f83" + integrity sha512-mjmzmv12YIG/G8JQdQuz2MUDShEJ6teYpT5bmWA4q7iwoGen8xtt3twF3OvzIUl+Q06aWIjvnwQUKvQ6TtMRjg== + +acorn@^7.0.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.0.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.4.tgz#caba24b08185c3b56e3168e97d15ed17f4d31fd0" + integrity sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +agentkeepalive@3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.4.1.tgz#aa95aebc3a749bca5ed53e3880a09f5235b48f0c" + integrity sha512-MPIwsZU9PP9kOrZpyu2042kYA8Fdt/AedQYkYXucHgF9QoD9dXVp0ypuGnHXSR0hTstBxdt85Xkh4JolYfK5wg== + dependencies: + 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" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +anser@1.4.9: + version "1.4.9" + resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760" + integrity sha512-AI+BjTeGt2+WFk4eWcqbQ7snZpDBt8SaLlj0RT2h5xfdWaiy51OjYvqwMrNzJLGy8iOAL6nKDITWO+rd4MkYEA== + +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-escapes@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +any-observable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" + integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== + +anymatch@~3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +app-module-path@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5" + integrity sha1-ZBqlXft9am8KgUHEucCqULbCTdU= + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-includes-with-glob@^3.0.6: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-includes-with-glob/-/array-includes-with-glob-3.1.0.tgz#f04e8172f231ab8261e52bfe9756b65c08b87ab9" + integrity sha512-/PZEKASyXWmUTkNhuxnmqybv1CmIdY5rp3axLy3Dv6SYfaBb+EgS7Nl991mquHT1N2u0YAnE3IOafVNRM6Y9dw== + dependencies: + "@babel/runtime" "^7.14.0" + 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" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flatmap@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" + integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + function-bind "^1.1.1" + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +assert@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== + dependencies: + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +ast-module-types@^2.3.2, ast-module-types@^2.4.0, ast-module-types@^2.6.0, ast-module-types@^2.7.0, ast-module-types@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-2.7.1.tgz#3f7989ef8dfa1fdb82dfe0ab02bdfc7c77a57dd3" + integrity sha512-Rnnx/4Dus6fn7fTqdeLEAn5vUll5w7/vts0RN608yFa6si/rDOUonlIIiwugHBFWjylHjxm9owoSZn71KwG4gw== + +ast-types@0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" + integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async-retry@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.2.3.tgz#a6521f338358d322b1a0012b79030c6f411d1ce0" + integrity sha512-tfDb02Th6CE6pJUF2gjW5ZVjsgwlucVXOEQMvEX9JgSJMs9gAX+Nz3xRuJBKuUYjTSYORqvDBORdAQ3LU59g7Q== + dependencies: + retry "0.12.0" + +async-retry@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.1.tgz#139f31f8ddce50c0870b0ba558a6079684aaed55" + integrity sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA== + dependencies: + retry "0.12.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +auto-bind@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb" + integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ== + +autoprefixer@^10.2.4: + version "10.2.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.6.tgz#aadd9ec34e1c98d403e01950038049f0eb252949" + integrity sha512-8lChSmdU6dCNMCQopIf4Pe5kipkAGj/fvTMslCsih0uHpOrXOPUEVOmYMMqmw3cekQkSD7EhIeuYl5y0BLdKqg== + dependencies: + browserslist "^4.16.6" + caniuse-lite "^1.0.30001230" + colorette "^1.2.2" + fraction.js "^4.1.1" + normalize-range "^0.1.2" + postcss-value-parser "^4.1.0" + +autoprefixer@^9.6.1: + version "9.8.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" + integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + colorette "^1.2.1" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + +available-typed-arrays@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz#9e0ae84ecff20caae6a94a1c3bc39b955649b7a9" + integrity sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA== + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-syntax-jsx@6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= + +babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: + version "7.0.0-beta.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" + integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== + +babel-preset-fbjs@^3.3.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" + integrity sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-syntax-class-properties" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoped-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-member-expression-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-super" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-property-literals" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" + +backo2@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.0.2, base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + +body-scroll-lock@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz#c1392d9217ed2c3e237fee1e910f6cdd80b7aaec" + integrity sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg== + +bowser@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-zlib@0.2.0, browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@4.16.6, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.6.4: + version "4.16.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" + integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== + dependencies: + caniuse-lite "^1.0.30001219" + colorette "^1.2.2" + electron-to-chromium "^1.3.723" + escalade "^3.1.1" + node-releases "^1.1.71" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" + integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +buffer@^4.3.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^5.5.0, buffer@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@3.1.0, bytes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@4.1.2, camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +camelcase-keys@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== + dependencies: + camelcase "^5.3.1" + map-obj "^4.0.0" + quick-lru "^4.0.1" + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001230: + version "1.0.30001230" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz#8135c57459854b2240b57a4a6786044bdc5a9f71" + integrity sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ== + +capital-case@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.0.0.tgz#6e98081ed2d17faab615eb52ac66ec1fe6209e72" + integrity sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^1.0.0, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" + integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +change-case-all@1.0.14: + version "1.0.14" + resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.14.tgz#bac04da08ad143278d0ac3dda7eccd39280bfba1" + integrity sha512-CWVm2uT7dmSHdO/z1CXT/n47mWonyypzBbuCy5tN7uMg22BsfkhwT6oHmFCAk+gL1LOOxhdbB9SZz3J1KTY3gA== + dependencies: + change-case "^4.1.2" + is-lower-case "^2.0.2" + is-upper-case "^2.0.2" + lower-case "^2.0.2" + lower-case-first "^2.0.2" + sponge-case "^1.0.1" + swap-case "^2.0.2" + title-case "^3.0.3" + upper-case "^2.0.2" + upper-case-first "^2.0.2" + +change-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" + integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== + dependencies: + camel-case "^4.1.2" + capital-case "^1.0.4" + constant-case "^3.0.4" + dot-case "^3.0.4" + header-case "^2.0.4" + no-case "^3.0.4" + param-case "^3.0.4" + pascal-case "^3.1.2" + path-case "^3.0.4" + sentence-case "^3.0.4" + snake-case "^3.0.4" + tslib "^2.0.3" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +chokidar@3.5.1, chokidar@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.3.1" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +classnames@*, classnames@^2.2.6: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + +classnames@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^2.0.0, cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.0.tgz#36c7dc98fb6a9a76bd6238ec3f77e2425627e939" + integrity sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q== + +cli-truncate@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" + integrity sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ= + dependencies: + slice-ansi "0.0.4" + string-width "^1.0.1" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +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" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +color-convert@^1.9.0, color-convert@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014" + integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e" + integrity sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.4" + +colorette@^1.2.1, colorette@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" + integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.13.0, commander@^2.16.0, commander@^2.20.3, commander@^2.8.1: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +commander@^6.0.0, commander@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + +common-tags@1.8.0, common-tags@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +compare-versions@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" + integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +constant-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" + integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case "^2.0.2" + +constants-browserify@1.0.0, constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +convert-source-map@1.7.0, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +cookie@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig-toml-loader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig-toml-loader/-/cosmiconfig-toml-loader-1.0.0.tgz#0681383651cceff918177debe9084c0d3769509b" + integrity sha512-H/2gurFWVi7xXvCyvsWRLCMekl4tITJcX0QEsDMpzxtuxDyM59xLatYNg4s/k9AA/HdtCYfj2su8mgA0GSDLDA== + dependencies: + "@iarna/toml" "^2.2.5" + +cosmiconfig@7.0.0, cosmiconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" + integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-fetch@3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c" + integrity sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ== + dependencies: + node-fetch "2.6.1" + +cross-fetch@3.1.4, cross-fetch@^3.0.4, cross-fetch@^3.0.6: + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== + dependencies: + node-fetch "2.6.1" + +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-browserify@3.12.0, crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-blank-pseudo@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" + integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== + dependencies: + postcss "^7.0.5" + +css-has-pseudo@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" + integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + +css-prefers-color-scheme@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" + integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== + dependencies: + postcss "^7.0.5" + +css-unit-converter@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.2.tgz#4c77f5a1954e6dbff60695ecb214e3270436ab21" + integrity sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA== + +css.escape@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s= + +cssdb@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" + integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-simple@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssnano-preset-simple/-/cssnano-preset-simple-2.0.0.tgz#b55e72cb970713f425560a0e141b0335249e2f96" + integrity sha512-HkufSLkaBJbKBFx/7aj5HmCK9Ni/JedRQm0mT2qBzMG/dEuJOLnMt2lK6K1rwOOyV4j9aSY+knbW9WoS7BYpzg== + dependencies: + caniuse-lite "^1.0.30001202" + +cssnano-simple@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssnano-simple/-/cssnano-simple-2.0.0.tgz#930d9dcd8ba105c5a62ce719cb00854da58b5c05" + integrity sha512-0G3TXaFxlh/szPEG/o3VcmCwl0N3E60XNb9YZZijew5eIs6fLjJuOPxQd9yEBaX2p/YfJtt49i4vYi38iH6/6w== + dependencies: + cssnano-preset-simple "^2.0.0" + +csstype@^3.0.2: + version "3.0.8" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" + integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== + +data-uri-to-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" + integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== + +dataloader@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.0.0.tgz#41eaf123db115987e21ca93c005cd7753c55fe6f" + integrity sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ== + +date-fns@^1.27.2: + version "1.30.1" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" + integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== + +debounce@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + +debug@2: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.2.1, debug@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + +debug@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decamelize-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.1.0, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decomment@^0.9.2: + version "0.9.4" + resolved "https://registry.yarnpkg.com/decomment/-/decomment-0.9.4.tgz#fa40335bd90e3826d5c1984276e390525ff856d5" + integrity sha512-8eNlhyI5cSU4UbBlrtagWpR03dqXcE5IR9zpe7PnO6UzReXDskucsD8usgrzUmQ6qJ3N82aws/p/mu/jqbURWw== + dependencies: + esprima "4.0.1" + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "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: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +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" + integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== + +dependency-tree@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-7.2.2.tgz#2366c96c0a905adfc19e9ed8dcdbfcb93476dfb5" + integrity sha512-WWZJpNuMWqEM97CGykmyKLjjUWGVGkRRMSIEBWk5izmugxmivnItg4MMHkDzuvmB/7vglhudEoc5wyMp5ODD+Q== + dependencies: + commander "^2.20.3" + debug "^4.2.1" + filing-cabinet "^2.6.0" + precinct "^6.3.1" + typescript "^3.9.7" + +dequal@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" + integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +detect-indent@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" + integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== + +detective-amd@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detective-amd/-/detective-amd-3.1.0.tgz#92daee3214a0ca4522646cf333cac90a3fca6373" + integrity sha512-G7wGWT6f0VErjUkE2utCm7IUshT7nBh7aBBH2VBOiY9Dqy2DMens5iiOvYCuhstoIxRKLrnOvVAz4/EyPIAjnw== + dependencies: + ast-module-types "^2.7.0" + escodegen "^2.0.0" + get-amd-module-type "^3.0.0" + node-source-walk "^4.0.0" + +detective-cjs@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/detective-cjs/-/detective-cjs-3.1.1.tgz#18da3e39a002d2098a1123d45ce1de1b0d9045a0" + integrity sha512-JQtNTBgFY6h8uT6pgph5QpV3IyxDv+z3qPk/FZRDT9TlFfm5dnRtpH39WtQEr1khqsUxVqXzKjZHpdoQvQbllg== + dependencies: + ast-module-types "^2.4.0" + node-source-walk "^4.0.0" + +detective-es6@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/detective-es6/-/detective-es6-2.2.0.tgz#8f2baba3f8cd90a5cfd748f5ac436f0158ed2585" + integrity sha512-fSpNY0SLER7/sVgQZ1NxJPwmc9uCTzNgdkQDhAaj8NPYwr7Qji9QBcmbNvtMCnuuOGMuKn3O7jv0An+/WRWJZQ== + dependencies: + node-source-walk "^4.0.0" + +detective-less@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/detective-less/-/detective-less-1.0.2.tgz#a68af9ca5f69d74b7d0aa190218b211d83b4f7e3" + integrity sha512-Rps1xDkEEBSq3kLdsdnHZL1x2S4NGDcbrjmd4q+PykK5aJwDdP5MBgrJw1Xo+kyUHuv3JEzPqxr+Dj9ryeDRTA== + dependencies: + debug "^4.0.0" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-postcss@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detective-postcss/-/detective-postcss-3.0.1.tgz#511921951f66135e17d0ece2e7604c6e4966c9c6" + integrity sha512-tfTS2GdpUal5NY0aCqI4dpEy8Xfr88AehYKB0iBIZvo8y2g3UsrcDnrp9PR2FbzoW7xD5Rip3NJW7eCSvtqdUw== + dependencies: + debug "^4.1.1" + is-url "^1.2.4" + postcss "^7.0.2" + postcss-values-parser "^1.5.0" + +detective-sass@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detective-sass/-/detective-sass-3.0.1.tgz#496b819efd1f5c4dd3f0e19b43a8634bdd6927c4" + integrity sha512-oSbrBozRjJ+QFF4WJFbjPQKeakoaY1GiR380NPqwdbWYd5wfl5cLWv0l6LsJVqrgWfFN1bjFqSeo32Nxza8Lbw== + dependencies: + debug "^4.1.1" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-scss@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/detective-scss/-/detective-scss-2.0.1.tgz#06f8c21ae6dedad1fccc26d544892d968083eaf8" + integrity sha512-VveyXW4WQE04s05KlJ8K0bG34jtHQVgTc9InspqoQxvnelj/rdgSAy7i2DXAazyQNFKlWSWbS+Ro2DWKFOKTPQ== + dependencies: + debug "^4.1.1" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-stylus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detective-stylus/-/detective-stylus-1.0.0.tgz#50aee7db8babb990381f010c63fabba5b58e54cd" + integrity sha1-UK7n24uruZA4HwEMY/q7pbWOVM0= + +detective-typescript@^5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/detective-typescript/-/detective-typescript-5.8.0.tgz#c46776571e26bad6c9ada020cb3cb4e5625d1311" + integrity sha512-SrsUCfCaDTF64QVMHMidRal+kmkbIc5zP8cxxZPsomWx9vuEUjBlSJNhf7/ypE5cLdJJDI4qzKDmyzqQ+iz/xg== + dependencies: + "@typescript-eslint/typescript-estree" "^2.29.0" + ast-module-types "^2.6.0" + node-source-walk "^4.2.0" + typescript "^3.8.3" + +detective@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" + integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== + dependencies: + acorn-node "^1.6.1" + defined "^1.0.0" + minimist "^1.1.1" + +didyoumean@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.1.tgz#e92edfdada6537d484d73c0172fd1eba0c4976ff" + integrity sha1-6S7f2tplN9SE1zwBcv0eugxJdv8= + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +domain-browser@4.19.0: + version "4.19.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1" + integrity sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ== + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dot-object@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/dot-object/-/dot-object-2.1.4.tgz#c6c54e9fca510b4d0ea4d65acf33726963843b5f" + integrity sha512-7FXnyyCLFawNYJ+NhkqyP9Wd2yzuo+7n9pGiYpkmXCTYa8Ci2U0eUNDVg5OuO5Pm6aFXI2SWN8/N/w7SJWu1WA== + dependencies: + commander "^4.0.0" + glob "^7.1.5" + +dotenv@^8.2.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +electron-to-chromium@^1.3.723: + version "1.3.740" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.740.tgz#e38b7d2b848f632191b643e6dabca51be2162922" + integrity sha512-Mi2m55JrX2BFbNZGKYR+2ItcGnR4O5HhrvgoRRyZQlaMGQULqDhoGkLWHzJoshSzi7k1PUofxcDbNhlFrDZNhg== + +elegant-spinner@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" + integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +email-validator@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed" + integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encoding@0.1.13: + 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" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" + integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +enquirer@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +errno@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.2.tgz#6eb518b640262e8ddcbd48e0bc8549f82efd48a7" + integrity sha512-byRiNIQXE6HWNySaU6JohoNXzYgbBjztwFnBLUTiJmWXjaU9bSq3urQLUlNLQ292tc+gc07zYZXNZjaOoAX3sw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.3" + is-string "^1.0.6" + object-inspect "^1.10.3" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "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@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +esprima@4.0.1, esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + +events@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extract-files@9.0.0, extract-files@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a" + integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ== + +fast-glob@^3.1.1, fast-glob@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" + integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastq@^1.6.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" + integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +fbjs-css-vars@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== + +fbjs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.0.tgz#0907067fb3f57a78f45d95f1eacffcacd623c165" + integrity sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg== + dependencies: + cross-fetch "^3.0.4" + fbjs-css-vars "^1.0.0" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + +figures@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +figures@^3.0.0, figures@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-exists-dazinatorfork@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/file-exists-dazinatorfork/-/file-exists-dazinatorfork-1.0.2.tgz#cd8d0d85f63e39dc81eceb0b687c44a2cca95c47" + integrity sha512-r70c72ln2YHzQINNfxDp02hAhbGkt1HffZ+Du8oetWDLjDtFja/Lm10lUaSh9e+wD+7VDvPee0b0C9SAy8pWZg== + +filing-cabinet@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/filing-cabinet/-/filing-cabinet-2.6.0.tgz#3d4d5093a98b6fae84cf282e8bded1b8ad5f9c0c" + integrity sha512-7kSlTScEkxoYKXCix7tAQ52ZeIHcx7ZWWArEZgXY+eTMe6yDYFdDhHdkXm9rSmvrrpzdZeR1wiufS1rUt4OzMA== + dependencies: + app-module-path "^2.2.0" + commander "^2.13.0" + debug "^4.1.1" + decomment "^0.9.2" + enhanced-resolve "^4.1.0" + is-relative-path "^1.0.2" + module-definition "^3.0.0" + module-lookup-amd "^6.1.0" + resolve "^1.11.1" + resolve-dependency-path "^2.0.0" + sass-lookup "^3.0.0" + stylus-lookup "^3.0.1" + typescript "^3.0.3" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-cache-dir@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-versions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" + integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== + dependencies: + semver-regex "^3.1.2" + +find@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/find/-/find-0.3.0.tgz#4082e8fc8d8320f1a382b5e4f521b9bc50775cb8" + integrity sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw== + dependencies: + traverse-chain "~0.1.0" + +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= + +form-data@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fraction.js@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff" + integrity sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg== + +fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.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" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-amd-module-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-amd-module-type/-/get-amd-module-type-3.0.0.tgz#bb334662fa04427018c937774570de495845c288" + integrity sha512-99Q7COuACPfVt18zH9N4VAMyb81S6TUgJm2NgV6ERtkh9VIkAaByZkW530wl3lLN5KTtSrK9jVLxYsoP5hQKsw== + dependencies: + ast-module-types "^2.3.2" + node-source-walk "^4.0.0" + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-orientation@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/get-orientation/-/get-orientation-1.1.2.tgz#20507928951814f8a91ded0a0e67b29dfab98947" + integrity sha512-/pViTfifW+gBbh/RnlFYHINvELT9Znt+SYyDKAUL6uV6By019AK/s+i9XP4jSwq7lwP38Fd8HVeTxym3+hkwmQ== + dependencies: + stream-parser "^0.3.1" + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +glob-parent@^5.1.0, glob-parent@~5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.5, glob@^7.1.6: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb" + integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +gonzales-pe@^4.2.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" + integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== + dependencies: + minimist "^1.2.5" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + +graphql-config@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-3.3.0.tgz#24c3672a427cb67c0c717ca3b9d70e9f0c9e752b" + integrity sha512-mSQIsPMssr7QrgqhnjI+CyVH6oQgCrgS6irHsTvwf7RFDRnR2k9kqpQOQgVoOytBSn0DOYryS0w0SAg9xor/Jw== + dependencies: + "@endemolshinegroup/cosmiconfig-typescript-loader" "3.0.2" + "@graphql-tools/graphql-file-loader" "^6.0.0" + "@graphql-tools/json-file-loader" "^6.0.0" + "@graphql-tools/load" "^6.0.0" + "@graphql-tools/merge" "^6.0.0" + "@graphql-tools/url-loader" "^6.0.0" + "@graphql-tools/utils" "^7.0.0" + cosmiconfig "7.0.0" + cosmiconfig-toml-loader "1.0.0" + minimatch "3.0.4" + string-env-interpolation "1.0.1" + +graphql-request@^3.3.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.4.0.tgz#3a400cd5511eb3c064b1873afb059196bbea9c2b" + integrity sha512-acrTzidSlwAj8wBNO7Q/UQHS8T+z5qRGquCQRv9J1InwR01BBWV9ObnoE+JS5nCCEj8wSGS0yrDXVDoRiKZuOg== + dependencies: + cross-fetch "^3.0.6" + extract-files "^9.0.0" + form-data "^3.0.0" + +graphql-tag@^2.11.0: + version "2.12.4" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.4.tgz#d34066688a4f09e72d6f4663c74211e9b4b7c4bf" + integrity sha512-VV1U4O+9x99EkNpNmCUV5RZwq6MnK4+pGbRYWG+lA/m3uo7TSqJF81OkcOP148gFP6fzdl7JWYBrwWVTS9jXww== + dependencies: + tslib "^2.1.0" + +graphql-ws@^4.4.1: + version "4.5.1" + resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-4.5.1.tgz#d9dc6e047c6d4ddb928ccbfb3ca3022580a89925" + integrity sha512-GE7vCMKe2D7fc0ugkM1V8QMneHcbV9c3BpPBzdlW/Uzkqv0F/zZq9DDHxLzg55ZhE5OSLL+n/gyqAMPgH59hcw== + +graphql@^15.4.0: + version "15.5.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5" + integrity sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA== + +graphviz@0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/graphviz/-/graphviz-0.0.9.tgz#0bbf1df588c6a92259282da35323622528c4bbc4" + integrity sha512-SmoY2pOtcikmMCqCSy2NO1YsRfu9OO0wpTlOYW++giGjfX1a6gax/m1Fo8IdUd0/3H15cTOfR1SMKwohj4LKsg== + dependencies: + temp "~0.4.0" + +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== + dependencies: + duplexer "^0.1.2" + +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +header-case@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" + integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== + dependencies: + capital-case "^1.0.4" + tslib "^2.0.3" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== + +http-cache-semantics@^4.0.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-errors@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +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" + +https-browserify@1.0.0, https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + +husky@^4.3.8: + version "4.3.8" + resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" + integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== + dependencies: + chalk "^4.0.0" + ci-info "^2.0.0" + compare-versions "^3.6.0" + cosmiconfig "^7.0.0" + find-versions "^4.0.0" + opencollective-postinstall "^2.0.2" + pkg-dir "^5.0.0" + please-upgrade-node "^3.2.0" + slash "^3.0.0" + which-pm-runs "^1.0.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + 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, ieee754@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +immutability-helper@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-3.1.1.tgz#2b86b2286ed3b1241c9e23b7b21e0444f52f77b7" + integrity sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ== + +immutable@~3.7.6: + version "3.7.6" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" + integrity sha1-E7TTyxK++hVIKib+Gy665kAHHks= + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-from@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966" + integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ== + dependencies: + resolve-from "^5.0.0" + +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inquirer@^7.3.3: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +is-absolute@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" + integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== + dependencies: + is-relative "^1.0.0" + is-windows "^1.0.1" + +is-arguments@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" + integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== + dependencies: + call-bind "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" + integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" + integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng== + dependencies: + call-bind "^1.0.2" + +is-callable@^1.1.4, is-callable@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" + integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== + +is-core-module@^2.2.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" + integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5" + integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-function@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.9.tgz#e5f82c2323673e7fcad3d12858c83c4039f6399c" + integrity sha512-ZJ34p1uvIfptHCN7sFTjGibB9/oBg17sHqzDLfuwhvmN/qLVvIQXRQ8licZQ35WJ8KuEQt/etnnzQFI9C9Ue/A== + +is-glob@4.0.1, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-interactive@^1.0.0: + version "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-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" + integrity sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ== + dependencies: + tslib "^2.0.3" + +is-nan@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-number-object@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" + integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-observable@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-1.1.0.tgz#b3e986c8f44de950867cab5403f5a3465005975e" + integrity sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA== + dependencies: + symbol-observable "^1.1.0" + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-promise@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" + integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== + +is-promise@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + +is-regex@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" + integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== + dependencies: + call-bind "^1.0.2" + has-symbols "^1.0.2" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-relative-path@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-relative-path/-/is-relative-path-1.0.2.tgz#091b46a0d67c1ed0fe85f1f8cfdde006bb251d46" + integrity sha1-CRtGoNZ8HtD+hfH4z93gBrslHUY= + +is-relative@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" + integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== + dependencies: + is-unc-path "^1.0.0" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + +is-string@^1.0.5, is-string@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" + integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.5.tgz#f32e6e096455e329eb7b423862456aa213f0eb4e" + integrity sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug== + dependencies: + available-typed-arrays "^1.0.2" + call-bind "^1.0.2" + es-abstract "^1.18.0-next.2" + foreach "^2.0.5" + has-symbols "^1.0.1" + +is-unc-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" + integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== + dependencies: + unc-path-regex "^0.1.2" + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-upper-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-2.0.2.tgz#f1105ced1fe4de906a5f39553e7d3803fd804649" + integrity sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ== + dependencies: + tslib "^2.0.3" + +is-url@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== + +is-windows@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +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== + dependencies: + node-fetch "^2.6.1" + whatwg-fetch "^3.4.1" + +isomorphic-ws@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + +iterall@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" + integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== + +jest-worker@27.0.0-next.5: + version "27.0.0-next.5" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.0-next.5.tgz#5985ee29b12a4e191f4aae4bb73b97971d86ec28" + integrity sha512-mk0umAQ5lT+CaOJ+Qp01N6kz48sJG2kr2n1rX0koqKf6FIygQV0qLOdN9SCYID4IVeSigDOcPeGLozdMLYfb5g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +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" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= + dependencies: + jsonify "~0.0.0" + +json-to-pretty-yaml@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz#f4cd0bd0a5e8fe1df25aaf5ba118b099fd992d5b" + integrity sha1-9M0L0KXo/h3yWq9boRiwmf2ZLVs= + dependencies: + remedial "^1.0.7" + remove-trailing-spaces "^1.0.6" + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= + +jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +keen-slider@^5.2.4: + version "5.4.1" + resolved "https://registry.yarnpkg.com/keen-slider/-/keen-slider-5.4.1.tgz#a6444b8afd28da1d15d7f769d531c2e00414bde0" + integrity sha512-CRBQDs7sQRxDRdQbHECuV2+IETD6UGp1bqnyNlbGM4trW9ObUTY39DWl/dLGh91x8qEepkCiYAO+w0B9gjEtkg== + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +kind-of@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +latest-version@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +lint-staged@^10.5.3: + version "10.5.4" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.5.4.tgz#cd153b5f0987d2371fc1d2847a409a2fe705b665" + integrity sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg== + dependencies: + chalk "^4.1.0" + cli-truncate "^2.1.0" + commander "^6.2.0" + cosmiconfig "^7.0.0" + debug "^4.2.0" + dedent "^0.7.0" + enquirer "^2.3.6" + execa "^4.1.0" + listr2 "^3.2.2" + log-symbols "^4.0.0" + micromatch "^4.0.2" + normalize-path "^3.0.0" + please-upgrade-node "^3.2.0" + string-argv "0.3.1" + stringify-object "^3.3.0" + +listr-silent-renderer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" + integrity sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4= + +listr-update-renderer@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz#4ea8368548a7b8aecb7e06d8c95cb45ae2ede6a2" + integrity sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA== + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + elegant-spinner "^1.0.1" + figures "^1.7.0" + indent-string "^3.0.0" + log-symbols "^1.0.2" + log-update "^2.3.0" + strip-ansi "^3.0.1" + +listr-verbose-renderer@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz#f1132167535ea4c1261102b9f28dac7cba1e03db" + integrity sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw== + dependencies: + chalk "^2.4.1" + cli-cursor "^2.1.0" + date-fns "^1.27.2" + figures "^2.0.0" + +listr2@^3.2.2: + version "3.8.4" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.8.4.tgz#58ef278a430509d072c568d96d87a4357813638b" + integrity sha512-DX+iKRcxaGbBjoLJBQlGceZoqdhV6Z54wpsvIVoVKNJ/lEXK8KhGhLaZnIGKRQmDmtJOtyNSnnKFUS1qn+jqsw== + dependencies: + cli-truncate "^2.1.0" + colorette "^1.2.2" + figures "^3.2.0" + indent-string "^4.0.0" + log-update "^4.0.0" + p-map "^4.0.0" + rxjs "^6.6.7" + through "^2.3.8" + wrap-ansi "^7.0.0" + +listr@^0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586" + integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA== + dependencies: + "@samverschueren/stream-to-observable" "^0.3.0" + is-observable "^1.1.0" + is-promise "^2.1.0" + is-stream "^1.1.0" + listr-silent-renderer "^1.1.1" + listr-update-renderer "^0.5.0" + listr-verbose-renderer "^0.5.0" + p-map "^2.0.0" + rxjs "^6.3.3" + +loader-utils@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +loader-utils@^1.0.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +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" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.get@^4: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + +lodash.isboolean@^3.0.3: + version "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" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + +lodash.random@^3.2.0: + version "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" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= + +lodash.toarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" + integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE= + +lodash.topath@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" + integrity sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak= + +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, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg= + dependencies: + chalk "^1.0.0" + +log-symbols@^4.0.0, log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-update@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" + integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg= + dependencies: + ansi-escapes "^3.0.0" + cli-cursor "^2.0.0" + wrap-ansi "^3.0.1" + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +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" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-2.0.2.tgz#64c2324a2250bf7c37c5901e76a5b5309301160b" + integrity sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg== + dependencies: + tslib "^2.0.3" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +madge@^3.8.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/madge/-/madge-3.12.0.tgz#727c1ebb268150d52e6d0c3ccd382b4c7bd0bf19" + integrity sha512-9kA2W5RIbvH25CWc8tzPNn1X47AOcHEEwZJxWAMxhEOKEziVR1iMCbGCFUea5tWXs/A+xgJF59o/oSbNkOXpeg== + dependencies: + chalk "^4.1.0" + commander "^5.1.0" + commondir "^1.0.1" + debug "^4.0.1" + dependency-tree "^7.2.2" + detective-amd "^3.0.0" + detective-cjs "^3.1.1" + detective-es6 "^2.1.0" + detective-less "^1.0.2" + detective-postcss "^3.0.1" + detective-sass "^3.0.1" + detective-scss "^2.0.1" + detective-stylus "^1.0.0" + detective-typescript "^5.8.0" + graphviz "0.0.9" + ora "^5.1.0" + pluralize "^8.0.0" + precinct "^6.3.1" + pretty-ms "^7.0.0" + rc "^1.2.7" + typescript "^3.9.5" + walkdir "^0.4.1" + +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@^1, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +map-cache@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-obj@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" + integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== + +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" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-7.1.1.tgz#7c01595e3d337fcb0ec4e8eed1666ea95903d306" + integrity sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA== + dependencies: + "@types/minimist" "^1.2.0" + camelcase-keys "^6.2.2" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^2.5.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.13.1" + yargs-parser "^18.1.3" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +meros@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/meros/-/meros-1.1.4.tgz#c17994d3133db8b23807f62bec7f0cb276cfd948" + integrity sha512-E9ZXfK9iQfG9s73ars9qvvvbSIkJZF5yOo9j4tcwM5tN8mUKfj/EKN5PzOr3ZH0y5wL7dLAHw3RVEfpQV9Q7VQ== + +micromatch@^4.0.0, micromatch@^4.0.2: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.47.0: + version "1.47.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c" + integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw== + +mime-types@^2.1.12: + version "2.1.30" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d" + integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg== + dependencies: + mime-db "1.47.0" + +mime@^2.3.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" + integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist-options@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" + integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + kind-of "^6.0.3" + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +modern-normalize@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/modern-normalize/-/modern-normalize-1.1.0.tgz#da8e80140d9221426bd4f725c6e11283d34f90b7" + integrity sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA== + +module-definition@^3.0.0, module-definition@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/module-definition/-/module-definition-3.3.1.tgz#fedef71667713e36988b93d0626a4fe7b35aebfc" + integrity sha512-kLidGPwQ2yq484nSD+D3JoJp4Etc0Ox9P0L34Pu/cU4X4HcG7k7p62XI5BBuvURWMRX3RPyuhOcBHbKus+UH4A== + dependencies: + ast-module-types "^2.7.1" + node-source-walk "^4.0.0" + +module-lookup-amd@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/module-lookup-amd/-/module-lookup-amd-6.2.0.tgz#70600008b3f26630fde9ef9ae6165ac69de6ecbb" + integrity sha512-uxHCj5Pw9psZiC1znjU2qPsubt6haCSsN9m7xmIdoTciEgfxUkE1vhtDvjHPuOXEZrVJhjKgkmkP+w73rRuelQ== + dependencies: + commander "^2.8.1" + debug "^4.1.0" + file-exists-dazinatorfork "^1.0.2" + find "^0.3.0" + requirejs "^2.3.5" + requirejs-config-file "^3.1.1" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.0.0, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +nanoid@^3.1.22, nanoid@^3.1.23: + version "3.1.23" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" + integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== + +native-url@0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.3.4.tgz#29c943172aed86c63cee62c8c04db7f5756661f8" + integrity sha512-6iM8R99ze45ivyH8vybJ7X0yekIcPf5GgLV5K0ENCbmRcaRIDoj37BC8iLEmaaBfqqb8enuZ5p0uhY+lVAbAcA== + dependencies: + querystring "^0.2.0" + +next-seo@^4.11.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-4.24.0.tgz#7c0447da00b8574dcda5c6979771a7f6efd24f55" + integrity sha512-9VQXfXAelhE+hAWzJ4azigQaW3FPX0kU0eYKFQXKsQjgY7AWtukjRGXls0oSIk8khhDJwmCt46EwsO9n5DDW6Q== + +next-themes@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.4.tgz#fb06a9d03887201dd8fdd75fc1c84f406988f61e" + integrity sha512-j0bJJ6INanFsniCL31j1ZhjNaoqIFOaTeiUakbGpGxDz4+318Zp2ZfaorSjpUhzDWbXBKA3ZDE0DSUVWJ/8EsA== + +next-unused@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/next-unused/-/next-unused-0.0.3.tgz#e7560b30c64b91a4143450eee1cdb535eb85e51b" + integrity sha512-LrjyGL6gq3v7eOL2KNkmciDZCpJjt9QjEftQEr4oZ8o5zwoEvLqfn7mgv+9Qv+i39fDrEYlF436zfwpBHp7ahg== + dependencies: + madge "^3.8.0" + ts-loader "^7.0.0" + +next@^10.0.9-canary.5: + version "10.2.3" + resolved "https://registry.yarnpkg.com/next/-/next-10.2.3.tgz#5aa058a63626338cea91c198fda8f2715c058394" + integrity sha512-dkM1mIfnORtGyzw/Yme8RdqNxlCMZyi4Lqj56F01/yHbe1ZtOaJ0cyqqRB4RGiPhjGGh0319f8ddjDyO1605Ow== + dependencies: + "@babel/runtime" "7.12.5" + "@hapi/accept" "5.0.2" + "@next/env" "10.2.3" + "@next/polyfill-module" "10.2.3" + "@next/react-dev-overlay" "10.2.3" + "@next/react-refresh-utils" "10.2.3" + "@opentelemetry/api" "0.14.0" + assert "2.0.0" + ast-types "0.13.2" + browserify-zlib "0.2.0" + browserslist "4.16.6" + buffer "5.6.0" + caniuse-lite "^1.0.30001228" + chalk "2.4.2" + chokidar "3.5.1" + constants-browserify "1.0.0" + crypto-browserify "3.12.0" + cssnano-simple "2.0.0" + domain-browser "4.19.0" + encoding "0.1.13" + etag "1.8.1" + find-cache-dir "3.3.1" + get-orientation "1.1.2" + https-browserify "1.0.0" + jest-worker "27.0.0-next.5" + native-url "0.3.4" + node-fetch "2.6.1" + node-html-parser "1.4.9" + node-libs-browser "^2.2.1" + os-browserify "0.3.0" + p-limit "3.1.0" + path-browserify "1.0.1" + pnp-webpack-plugin "1.6.4" + postcss "8.2.13" + process "0.11.10" + prop-types "15.7.2" + querystring-es3 "0.2.1" + raw-body "2.4.1" + react-is "16.13.1" + react-refresh "0.8.3" + stream-browserify "3.0.0" + stream-http "3.1.1" + string_decoder "1.3.0" + styled-jsx "3.3.2" + timers-browserify "2.0.12" + tty-browserify "0.0.1" + use-subscription "1.5.1" + util "0.12.3" + vm-browserify "1.1.2" + watchpack "2.1.1" + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-emoji@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" + integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw== + dependencies: + lodash.toarray "^4.4.0" + +node-fetch@2.6.1, node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + +node-html-parser@1.4.9: + version "1.4.9" + resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-1.4.9.tgz#3c8f6cac46479fae5800725edb532e9ae8fd816c" + integrity sha512-UVcirFD1Bn0O+TSmloHeHqZZCxHjvtIeGdVdGMhyZ8/PWlEiZaZ5iJzR189yKZr8p0FXN58BUeC7RHRkf/KYGw== + dependencies: + he "1.2.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-releases@^1.1.71: + version "1.1.72" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" + integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== + +node-source-walk@^4.0.0, node-source-walk@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-4.2.0.tgz#c2efe731ea8ba9c03c562aa0a9d984e54f27bc2c" + integrity sha512-hPs/QMe6zS94f5+jG3kk9E7TNm4P2SulrKiLWMzKszBfNZvL/V6wseHlTd7IvfW0NZWqPtK3+9yYNr+3USGteA== + dependencies: + "@babel/parser" "^7.0.0" + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nullthrows@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" + integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-hash@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + +object-inspect@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" + integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== + +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +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.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +opencollective-postinstall@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" + integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== + +opener@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" + integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +ora@^5.1.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.0.tgz#42eda4855835b9cd14d33864c97a3c95a3f56bf4" + integrity sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +os-browserify@0.3.0, os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-limit@3.1.0, p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-filepath@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" + integrity sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE= + dependencies: + is-absolute "^1.0.0" + map-cache "^0.2.0" + path-root "^0.1.1" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse-ms@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" + integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-browserify@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" + integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0= + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc= + dependencies: + path-root-regex "^0.1.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== + dependencies: + find-up "^5.0.0" + +platform@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" + integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== + +please-upgrade-node@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" + integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== + dependencies: + semver-compare "^1.0.0" + +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +pnp-webpack-plugin@1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" + integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg== + dependencies: + ts-pnp "^1.1.6" + +postcss-attribute-case-insensitive@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" + integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^6.0.2" + +postcss-color-functional-notation@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" + integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-gray@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" + integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-color-hex-alpha@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" + integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== + dependencies: + postcss "^7.0.14" + postcss-values-parser "^2.0.1" + +postcss-color-mod-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" + integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-rebeccapurple@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" + integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-custom-media@^7.0.8: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" + integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== + dependencies: + postcss "^7.0.14" + +postcss-custom-properties@^8.0.11: + version "8.0.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" + integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== + dependencies: + postcss "^7.0.17" + postcss-values-parser "^2.0.1" + +postcss-custom-selectors@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" + integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-dir-pseudo-class@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" + integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-double-position-gradients@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" + integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== + dependencies: + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-env-function@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" + integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-flexbugs-fixes@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz#9218a65249f30897deab1033aced8578562a6690" + integrity sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ== + dependencies: + postcss "^7.0.26" + +postcss-focus-visible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" + integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== + dependencies: + postcss "^7.0.2" + +postcss-focus-within@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" + integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== + dependencies: + postcss "^7.0.2" + +postcss-font-variant@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz#42d4c0ab30894f60f98b17561eb5c0321f502641" + integrity sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA== + dependencies: + postcss "^7.0.2" + +postcss-functions@^3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-functions/-/postcss-functions-3.0.0.tgz#0e94d01444700a481de20de4d55fb2640564250e" + integrity sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4= + dependencies: + glob "^7.1.2" + object-assign "^4.1.1" + postcss "^6.0.9" + postcss-value-parser "^3.3.0" + +postcss-gap-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" + integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== + dependencies: + postcss "^7.0.2" + +postcss-image-set-function@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" + integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-initial@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.4.tgz#9d32069a10531fe2ecafa0b6ac750ee0bc7efc53" + integrity sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg== + dependencies: + postcss "^7.0.2" + +postcss-js@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-3.0.3.tgz#2f0bd370a2e8599d45439f6970403b5873abda33" + integrity sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw== + dependencies: + camelcase-css "^2.0.1" + postcss "^8.1.6" + +postcss-lab-function@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" + integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-logical@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" + integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== + dependencies: + postcss "^7.0.2" + +postcss-media-minmax@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" + integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== + dependencies: + postcss "^7.0.2" + +postcss-nested@5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.5.tgz#f0a107d33a9fab11d7637205f5321e27223e3603" + integrity sha512-GSRXYz5bccobpTzLQZXOnSOfKl6TwVr5CyAQJUPub4nuRJSOECK5AqurxVgmtxP48p0Kc/ndY/YyS1yqldX0Ew== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-nesting@^7.0.0, postcss-nesting@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" + integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg== + dependencies: + postcss "^7.0.2" + +postcss-overflow-shorthand@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" + integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== + dependencies: + postcss "^7.0.2" + +postcss-page-break@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" + integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== + dependencies: + postcss "^7.0.2" + +postcss-place@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" + integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-preset-env@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5" + integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg== + dependencies: + autoprefixer "^9.6.1" + browserslist "^4.6.4" + caniuse-lite "^1.0.30000981" + css-blank-pseudo "^0.1.4" + css-has-pseudo "^0.10.0" + css-prefers-color-scheme "^3.1.1" + cssdb "^4.4.0" + postcss "^7.0.17" + postcss-attribute-case-insensitive "^4.0.1" + postcss-color-functional-notation "^2.0.1" + postcss-color-gray "^5.0.0" + postcss-color-hex-alpha "^5.0.3" + postcss-color-mod-function "^3.0.3" + postcss-color-rebeccapurple "^4.0.1" + postcss-custom-media "^7.0.8" + postcss-custom-properties "^8.0.11" + postcss-custom-selectors "^5.1.2" + postcss-dir-pseudo-class "^5.0.0" + postcss-double-position-gradients "^1.0.0" + postcss-env-function "^2.0.2" + postcss-focus-visible "^4.0.0" + postcss-focus-within "^3.0.0" + postcss-font-variant "^4.0.0" + postcss-gap-properties "^2.0.0" + postcss-image-set-function "^3.0.1" + postcss-initial "^3.0.0" + postcss-lab-function "^2.0.1" + postcss-logical "^3.0.0" + postcss-media-minmax "^4.0.0" + postcss-nesting "^7.0.0" + postcss-overflow-shorthand "^2.0.0" + postcss-page-break "^2.0.0" + postcss-place "^4.0.1" + postcss-pseudo-class-any-link "^6.0.0" + postcss-replace-overflow-wrap "^3.0.0" + postcss-selector-matches "^4.0.0" + postcss-selector-not "^4.0.0" + +postcss-pseudo-class-any-link@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" + integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-replace-overflow-wrap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" + integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== + dependencies: + postcss "^7.0.2" + +postcss-selector-matches@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" + integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-not@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz#263016eef1cf219e0ade9a913780fc1f48204cbf" + integrity sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.6" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + +postcss-values-parser@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-1.5.0.tgz#5d9fa63e2bcb0179ce48f3235303765eb89f3047" + integrity sha512-3M3p+2gMp0AH3da530TlX8kiO1nxdTnc3C6vr8dMxRLIlh8UYkz0/wcwptSXjhtx2Fr0TySI7a+BHDQ8NL7LaQ== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" + integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss@8.2.13: + version "8.2.13" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.13.tgz#dbe043e26e3c068e45113b1ed6375d2d37e2129f" + integrity sha512-FCE5xLH+hjbzRdpbRb1IMCvPv9yZx2QnDarBEYSN0N0HYk+TcXsEhwdFcFb+SRWOKzKGErhIEbBK2ogyLdTtfQ== + dependencies: + colorette "^1.2.2" + nanoid "^3.1.22" + source-map "^0.6.1" + +postcss@^6.0.9: + version "6.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + +postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.35" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" + integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.8: + version "8.3.0" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.0.tgz#b1a713f6172ca427e3f05ef1303de8b65683325f" + integrity sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ== + dependencies: + colorette "^1.2.2" + nanoid "^3.1.23" + source-map-js "^0.6.2" + +precinct@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/precinct/-/precinct-6.3.1.tgz#8ad735a8afdfc48b56ed39c9ad3bf999b6b928dc" + integrity sha512-JAwyLCgTylWminoD7V0VJwMElWmwrVSR6r9HaPWCoswkB4iFzX7aNtO7VBfAVPy+NhmjKb8IF8UmlWJXzUkOIQ== + dependencies: + commander "^2.20.3" + debug "^4.1.1" + detective-amd "^3.0.0" + detective-cjs "^3.1.1" + detective-es6 "^2.1.0" + detective-less "^1.0.2" + detective-postcss "^3.0.1" + detective-sass "^3.0.1" + detective-scss "^2.0.1" + detective-stylus "^1.0.0" + detective-typescript "^5.8.0" + module-definition "^3.3.0" + node-source-walk "^4.2.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +prettier@^2.0.5, prettier@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18" + integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w== + +pretty-hrtime@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" + integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= + +pretty-ms@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-7.0.1.tgz#7d903eaab281f7d8e03c66f867e239dc32fb73e8" + integrity sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q== + dependencies: + parse-ms "^2.1.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@0.11.10, process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +prop-types@15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +purgecss@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-3.1.3.tgz#26987ec09d12eeadc318e22f6e5a9eb0be094f41" + integrity sha512-hRSLN9mguJ2lzlIQtW4qmPS2kh6oMnA9RxdIYK8sz18QYqd6ePp4GNDl18oWHA1f2v2NEQIh51CO8s/E3YGckQ== + dependencies: + commander "^6.0.0" + glob "^7.0.0" + 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.1, querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystring@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" + integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-lru@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +raw-body@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" + integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA== + dependencies: + bytes "3.1.0" + http-errors "1.7.3" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.7, rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-dom@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + +react-is@16.13.1, react-is@^16.8.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-merge-refs@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz#73d88b892c6c68cbb7a66e0800faa374f4c38b06" + integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ== + +react-refresh@0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" + integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== + +react-ticker@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/react-ticker/-/react-ticker-1.2.2.tgz#12cda5ff8266c6fe90ffcd8c58e12ba1596ddf24" + integrity sha512-PXUujoPJvajxwOfosuuujlrBUrjgGp4FB4haWFOI25ujhMppW4SuLkiOdQ9AylrWN3yTHWdk2kbQWe3n9SjFGA== + +react@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.3.3, readable-stream@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== + dependencies: + picomatch "^2.2.1" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +reduce-css-calc@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz#7ef8761a28d614980dc0c982f772c93f7a99de03" + integrity sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg== + dependencies: + css-unit-converter "^1.1.1" + postcss-value-parser "^3.3.0" + +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== + +registry-auth-token@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" + integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== + dependencies: + rc "^1.2.8" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +relay-compiler@10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/relay-compiler/-/relay-compiler-10.1.0.tgz#fb4672cdbe9b54869a3a79759edd8c2d91609cbe" + integrity sha512-HPqc3N3tNgEgUH5+lTr5lnLbgnsZMt+MRiyS0uAVNhuPY2It0X1ZJG+9qdA3L9IqKFUNwVn6zTO7RArjMZbARQ== + dependencies: + "@babel/core" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/parser" "^7.0.0" + "@babel/runtime" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + babel-preset-fbjs "^3.3.0" + chalk "^4.0.0" + fb-watchman "^2.0.0" + fbjs "^3.0.0" + glob "^7.1.1" + immutable "~3.7.6" + nullthrows "^1.1.1" + relay-runtime "10.1.0" + signedsource "^1.0.0" + yargs "^15.3.1" + +relay-runtime@10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/relay-runtime/-/relay-runtime-10.1.0.tgz#4753bf36e95e8d862cef33608e3d98b4ed730d16" + integrity sha512-bxznLnQ1ST6APN/cFi7l0FpjbZVchWQjjhj9mAuJBuUqNNCh9uV+UTRhpQF7Q8ycsPp19LHTpVyGhYb0ustuRQ== + dependencies: + "@babel/runtime" "^7.0.0" + fbjs "^3.0.0" + +remedial@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/remedial/-/remedial-1.0.8.tgz#a5e4fd52a0e4956adbaf62da63a5a46a78c578a0" + integrity sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg== + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +remove-trailing-spaces@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/remove-trailing-spaces/-/remove-trailing-spaces-1.0.8.tgz#4354d22f3236374702f58ee373168f6d6887ada7" + integrity sha512-O3vsMYfWighyFbTd8hk8VaSj9UAGENxAtX+//ugIst2RMk5e03h6RoIS+0ylsFxY1gvmPuAY/PO4It+gPEeySA== + +replaceall@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/replaceall/-/replaceall-0.1.6.tgz#81d81ac7aeb72d7f5c4942adf2697a3220688d8e" + integrity sha1-gdgax663LX9cSUKt8ml6MiBojY4= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requirejs-config-file@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/requirejs-config-file/-/requirejs-config-file-3.1.2.tgz#de8c0b3eebdf243511c994a8a24b006f8b825997" + integrity sha512-sdLWywcDuNz7EIOhenSbRfT4YF84nItDv90coN2htbokjmU2QeyQuSBZILQUKNksepl8UPVU+hgYySFaDxbJPQ== + dependencies: + esprima "^4.0.0" + make-dir "^2.1.0" + stringify-object "^3.2.1" + +requirejs@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" + integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== + +resolve-dependency-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-dependency-path/-/resolve-dependency-path-2.0.0.tgz#11700e340717b865d216c66cabeb4a2a3c696736" + integrity sha512-DIgu+0Dv+6v2XwRaNWnumKu7GPufBBOr5I1gRPJHkvghrfCGOooJODFvgFimX/KRxk9j0whD2MnKHzM1jYvk9w== + +resolve-from@5.0.0, resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.10.0, resolve@^1.11.1, resolve@^1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +retry@0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^6.3.3, rxjs@^6.6.0, rxjs@^6.6.7: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass-lookup@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/sass-lookup/-/sass-lookup-3.0.0.tgz#3b395fa40569738ce857bc258e04df2617c48cac" + integrity sha512-TTsus8CfFRn1N44bvdEai1no6PqdmDiQUiqW5DlpmtT+tYnIt1tXtDIph5KA1efC+LmioJXSnCtUVpcK9gaKIg== + dependencies: + commander "^2.16.0" + +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +scuid@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/scuid/-/scuid-1.1.0.tgz#d3f9f920956e737a60f72d0e4ad280bf324d5dab" + integrity sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg== + +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= + +semver-regex@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.2.tgz#34b4c0d361eef262e07199dbef316d0f2ab11807" + integrity sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA== + +"semver@2 || 3 || 4 || 5", semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.2: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +sentence-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" + integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +setimmediate@^1.0.4, setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +shopify-buy@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/shopify-buy/-/shopify-buy-2.11.0.tgz#0f7cb52741395e4ae778c336f32ddf3fe67c2f35" + integrity sha512-bGjS1b/VCPvCjazSstlKwgLtK1WBotWom06/12loja8yfo/cWkLuJsakBbQe1uEIDiOLhKaR0M0CAXZFheYDug== + +signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +signedsource@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/signedsource/-/signedsource-1.0.0.tgz#1ddace4981798f93bd833973803d80d52e93ad6a" + integrity sha1-HdrOSYF5j5O9gzlzgD2A1S6TrWo= + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +sirv@^1.0.7: + version "1.0.12" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.12.tgz#d816c882b35489b3c63290e2f455ae3eccd5f652" + integrity sha512-+jQoCxndz7L2tqQL4ZyzfDhky0W/4ZJip3XoOuxyQWnAwMxindLl3Xv1qT4x1YX/re0leShvTm8Uk0kQspGhBg== + dependencies: + "@polka/url" "^1.0.0-next.15" + mime "^2.3.1" + totalist "^1.0.0" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +source-map-js@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" + integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== + +source-map-support@^0.5.17: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +source-map@0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f" + integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ== + +sponge-case@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sponge-case/-/sponge-case-1.0.1.tgz#260833b86453883d974f84854cdb63aecc5aef4c" + integrity sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA== + dependencies: + tslib "^2.0.3" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +stacktrace-parser@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== + dependencies: + type-fest "^0.7.1" + +"statuses@>= 1.5.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stream-browserify@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-http@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.1.1.tgz#0370a8017cf8d050b9a8554afe608f043eaff564" + integrity sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.4" + readable-stream "^3.6.0" + xtend "^4.0.2" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-parser@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/stream-parser/-/stream-parser-0.3.1.tgz#1618548694420021a1182ff0af1911c129761773" + integrity sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M= + dependencies: + debug "2" + +string-argv@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== + +string-env-interpolation@1.0.1, string-env-interpolation@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz#ad4397ae4ac53fe6c91d1402ad6f6a52862c7152" + integrity sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg== + +string-hash@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" + integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@1.3.0, string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +stringify-object@^3.2.1, stringify-object@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +strip-ansi@6.0.0, strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +styled-jsx@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-3.3.2.tgz#2474601a26670a6049fb4d3f94bd91695b3ce018" + integrity sha512-daAkGd5mqhbBhLd6jYAjYBa9LpxYCzsgo/f6qzPdFxVB8yoGbhxvzQgkC0pfmCVvW3JuAEBn0UzFLBfkHVZG1g== + dependencies: + "@babel/types" "7.8.3" + babel-plugin-syntax-jsx "6.18.0" + convert-source-map "1.7.0" + loader-utils "1.2.3" + source-map "0.7.3" + string-hash "1.1.3" + stylis "3.5.4" + stylis-rule-sheet "0.0.10" + +stylis-rule-sheet@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430" + integrity sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw== + +stylis@3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe" + integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q== + +stylus-lookup@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/stylus-lookup/-/stylus-lookup-3.0.2.tgz#c9eca3ff799691020f30b382260a67355fefdddd" + integrity sha512-oEQGHSjg/AMaWlKe7gqsnYzan8DLcGIHe0dUaFkucZZ14z4zjENRlQMCHT4FNsiWnJf17YN9OvrCfCoi7VvOyg== + dependencies: + commander "^2.8.1" + debug "^4.1.0" + +subscriptions-transport-ws@^0.9.18: + version "0.9.18" + resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.18.tgz#bcf02320c911fbadb054f7f928e51c6041a37b97" + integrity sha512-tztzcBTNoEbuErsVQpTN2xUNN/efAZXyCyL5m3x4t6SKrEiTL2N8SaKWBFWM4u56pL79ULif3zjyeq+oV+nOaA== + dependencies: + backo2 "^1.0.2" + eventemitter3 "^3.1.0" + iterall "^1.2.1" + symbol-observable "^1.0.4" + ws "^5.2.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0, supports-color@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +swap-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-2.0.2.tgz#671aedb3c9c137e2985ef51c51f9e98445bf70d9" + integrity sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw== + dependencies: + tslib "^2.0.3" + +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" + integrity sha512-SKGxcAfyijj/lE5ja5zVMDqJNudASH3WZPRUakDVOePTM18FnsXgugndjl9BSRwj+jokFCulMDe7F2pQL+VhEw== + dependencies: + dequal "2.0.2" + +symbol-observable@^1.0.4, symbol-observable@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + +sync-fetch@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/sync-fetch/-/sync-fetch-0.3.0.tgz#77246da949389310ad978ab26790bb05f88d1335" + integrity sha512-dJp4qg+x4JwSEW1HibAuMi0IIrBI3wuQr2GimmqB7OXR50wmwzfdusG+p39R9w3R6aFtZ2mzvxvWKQ3Bd/vx3g== + dependencies: + buffer "^5.7.0" + node-fetch "^2.6.1" + +tabbable@^5.1.5: + version "5.2.0" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.2.0.tgz#4fba60991d8bb89d06e5d9455c92b453acf88fb2" + integrity sha512-0uyt8wbP0P3T4rrsfYg/5Rg3cIJ8Shl1RJ54QMqYxm1TLdWqJD1u6+RQjr2Lor3wmfT7JRHkirIwy99ydBsyPg== + +tailwindcss@^2.0.4: + version "2.1.2" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.1.2.tgz#29402bf73a445faedd03df6d3b177e7b52b7c4a1" + integrity sha512-T5t+wwd+/hsOyRw2HJuFuv0LTUm3MUdHm2DJ94GPVgzqwPPFa9XxX0KlwLWupUuiOUj6uiKURCzYPHFcuPch/w== + dependencies: + "@fullhuman/postcss-purgecss" "^3.1.3" + bytes "^3.0.0" + chalk "^4.1.0" + chokidar "^3.5.1" + color "^3.1.3" + detective "^5.2.0" + didyoumean "^1.2.1" + dlv "^1.1.3" + fast-glob "^3.2.5" + fs-extra "^9.1.0" + html-tags "^3.1.0" + lodash "^4.17.21" + lodash.topath "^4.5.2" + modern-normalize "^1.0.0" + node-emoji "^1.8.1" + normalize-path "^3.0.0" + object-hash "^2.1.1" + parse-glob "^3.0.4" + postcss-functions "^3" + postcss-js "^3.0.3" + postcss-nested "5.0.5" + postcss-selector-parser "^6.0.4" + postcss-value-parser "^4.1.0" + pretty-hrtime "^1.0.3" + quick-lru "^5.1.1" + reduce-css-calc "^2.1.8" + resolve "^1.20.0" + +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +temp@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.4.0.tgz#671ad63d57be0fe9d7294664b3fc400636678a60" + integrity sha1-ZxrWPVe+D+nXKUZks/xABjZnimA= + +through@^2.3.6, through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +timers-browserify@2.0.12, timers-browserify@^2.0.4: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + +title-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/title-case/-/title-case-3.0.3.tgz#bc689b46f02e411f1d1e1d081f7c3deca0489982" + integrity sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA== + dependencies: + tslib "^2.0.3" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +totalist@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" + integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + +traverse-chain@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1" + integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE= + +trim-newlines@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" + integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA== + +ts-loader@^7.0.0: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.5.tgz#789338fb01cb5dc0a33c54e50558b34a73c9c4c5" + integrity sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig== + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + loader-utils "^1.0.2" + micromatch "^4.0.0" + semver "^6.0.0" + +ts-log@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.2.3.tgz#4da5640fe25a9fb52642cd32391c886721318efb" + integrity sha512-XvB+OdKSJ708Dmf9ore4Uf/q62AYDTzFcAdxc8KNML1mmAWywRFVt/dn1KYJH8Agt5UJNujfM3znU5PxgAzA2w== + +ts-node@^9: + version "9.1.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" + integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== + dependencies: + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + +ts-pnp@^1.1.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" + integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== + +tslib@^1.8.1, tslib@^1.9.0: + 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.0, tslib@^2.0.3, tslib@^2.1.0, tslib@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" + integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== + +tslib@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" + integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ== + +tslib@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + +tsutils@^3.17.1: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tty-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" + integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +typescript@^3.0.3, typescript@^3.8.3, typescript@^3.9.5, typescript@^3.9.7: + version "3.9.9" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674" + integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w== + +typescript@^4.0.3: + version "4.3.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805" + integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw== + +ua-parser-js@^0.7.18: + version "0.7.28" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" + integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unc-path-regex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unixify@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090" + integrity sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA= + dependencies: + normalize-path "^2.1.1" + +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +upper-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== + dependencies: + tslib "^2.0.3" + +upper-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" + integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== + dependencies: + tslib "^2.0.3" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use-subscription@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" + integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== + dependencies: + object-assign "^4.1.1" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util-nonempty@^3.0.6: + version "3.1.0" + resolved "https://registry.yarnpkg.com/util-nonempty/-/util-nonempty-3.1.0.tgz#927a9472ead1817afca159b209e5806523b752d3" + integrity sha512-OSZlWoCL74Go83Qw/aeZgSmFZnp9d06bF77b1eAOKipkPWhvxjRYB2nmKiGspoVjkJJEJimzxAgBFUQiUV/oZQ== + dependencies: + "@babel/runtime" "^7.14.0" + 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" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@0.12.3, util@^0.12.0: + version "0.12.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.3.tgz#971bb0292d2cc0c892dab7c6a5d37c2bec707888" + integrity sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +valid-url@1.0.9, valid-url@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" + integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +value-or-promise@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.6.tgz#218aa4794aa2ee24dcf48a29aba4413ed584747f" + integrity sha512-9r0wQsWD8z/BxPOvnwbPf05ZvFngXyouE9EKB+5GbYix+BYnAwrIChCUyFIinfbf2FL/U71z+CPpbnmTdxrwBg== + +vm-browserify@1.1.2, vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +walkdir@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39" + integrity sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ== + +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + +watchpack@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.1.1.tgz#e99630550fca07df9f90a06056987baa40a689c7" + integrity sha512-Oo7LXCmc1eE1AjyuSBmtC3+Wy4HcV8PxWh2kP6fOl8yTlNS7r0K9l1ao2lrrUza7V39Y3D/BbJgY8VeSlc5JKw== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +webpack-bundle-analyzer@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz#2f3c0ca9041d5ee47fa418693cf56b4a518b578b" + integrity sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA== + dependencies: + acorn "^8.0.4" + acorn-walk "^8.0.0" + chalk "^4.1.0" + commander "^6.2.0" + gzip-size "^6.0.0" + lodash "^4.17.20" + opener "^1.5.2" + sirv "^1.0.7" + ws "^7.3.1" + +whatwg-fetch@^3.4.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + +which-typed-array@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.4.tgz#8fcb7d3ee5adf2d771066fba7cf37e32fe8711ff" + integrity sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA== + dependencies: + available-typed-arrays "^1.0.2" + call-bind "^1.0.0" + es-abstract "^1.18.0-next.1" + foreach "^2.0.5" + function-bind "^1.1.1" + has-symbols "^1.0.1" + is-typed-array "^1.1.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" + integrity sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo= + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@7.4.5: + version "7.4.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1" + integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g== + +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + +ws@^7.3.1: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +xtend@^4.0.0, xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml-ast-parser@^0.0.43: + version "0.0.43" + resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz#e8a23e6fb4c38076ab92995c5dca33f3d3d7c9bb" + integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A== + +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^18.1.2, yargs-parser@^18.1.3: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^20.2.2: + version "20.2.7" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" + integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== + +yargs@^15.3.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^17.0.0: + version "17.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb" + integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==