mirror of
https://github.com/vercel/commerce.git
synced 2025-05-12 12:47:50 +00:00
Merge 482d2a0cd9254a09c1c4428c8ac36b32401618f4 into 610b0e86928bffeea94201dd0eeb9b62e9b1f5c0
This commit is contained in:
commit
d60377ef44
@ -5,3 +5,4 @@ SITE_NAME="Next.js Commerce"
|
||||
SHOPIFY_REVALIDATION_SECRET=""
|
||||
SHOPIFY_STOREFRONT_ACCESS_TOKEN=""
|
||||
SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com"
|
||||
NEXT_PUBLIC_SHOPIFY_SHOP_ID="[your-shopify-shop-id]"
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -36,3 +36,4 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
.idea
|
||||
|
45
README.md
45
README.md
@ -14,16 +14,22 @@ A Next.js 14 and App Router-ready ecommerce template featuring:
|
||||
- Styling with Tailwind CSS
|
||||
- Checkout and payments with Shopify
|
||||
- Automatic light/dark mode based on system settings
|
||||
- Shopify Analytics
|
||||
|
||||
<h3 id="v1-note"></h3>
|
||||
|
||||
> Note: Looking for Next.js Commerce v1? View the [code](https://github.com/vercel/commerce/tree/v1), [demo](https://commerce-v1.vercel.store), and [release notes](https://github.com/vercel/commerce/releases/tag/v1).
|
||||
> Note: Looking for Next.js Commerce v1? View
|
||||
> the [code](https://github.com/vercel/commerce/tree/v1), [demo](https://commerce-v1.vercel.store),
|
||||
> and [release notes](https://github.com/vercel/commerce/releases/tag/v1).
|
||||
|
||||
## Providers
|
||||
|
||||
Vercel will only be actively maintaining a Shopify version [as outlined in our vision and strategy for Next.js Commerce](https://github.com/vercel/commerce/pull/966).
|
||||
Vercel will only be actively maintaining a Shopify
|
||||
version [as outlined in our vision and strategy for Next.js Commerce](https://github.com/vercel/commerce/pull/966).
|
||||
|
||||
Vercel is happy to partner and work with any commerce provider to help them get a similar template up and running and listed below. Alternative providers should be able to fork this repository and swap out the `lib/shopify` file with their own implementation while leaving the rest of the template mostly unchanged.
|
||||
Vercel is happy to partner and work with any commerce provider to help them get a similar template up and running and
|
||||
listed below. Alternative providers should be able to fork this repository and swap out the `lib/shopify` file with
|
||||
their own implementation while leaving the rest of the template mostly unchanged.
|
||||
|
||||
- Shopify (this repository)
|
||||
- [BigCommerce](https://github.com/bigcommerce/nextjs-commerce) ([Demo](https://next-commerce-v2.vercel.app/))
|
||||
@ -34,21 +40,41 @@ Vercel is happy to partner and work with any commerce provider to help them get
|
||||
- [Umbraco](https://github.com/umbraco/Umbraco.VercelCommerce.Demo) ([Demo](https://vercel-commerce-demo.umbraco.com/))
|
||||
- [Wix](https://github.com/wix/nextjs-commerce) ([Demo](https://wix-nextjs-commerce.vercel.app/))
|
||||
|
||||
> Note: Providers, if you are looking to use similar products for your demo, you can [download these assets](https://drive.google.com/file/d/1q_bKerjrwZgHwCw0ovfUMW6He9VtepO_/view?usp=sharing).
|
||||
> Note: Providers, if you are looking to use similar products for your demo, you
|
||||
> can [download these assets](https://drive.google.com/file/d/1q_bKerjrwZgHwCw0ovfUMW6He9VtepO_/view?usp=sharing).
|
||||
|
||||
## Integrations
|
||||
|
||||
Integrations enable upgraded or additional functionality for Next.js Commerce
|
||||
|
||||
- [Orama](https://github.com/oramasearch/nextjs-commerce) ([Demo](https://vercel-commerce.oramasearch.com/))
|
||||
- Upgrades search to include typeahead with dynamic re-rendering, vector-based similarity search, and JS-based configuration.
|
||||
- Upgrades search to include typeahead with dynamic re-rendering, vector-based similarity search, and JS-based
|
||||
configuration.
|
||||
- Search runs entirely in the browser for smaller catalogs or on a CDN for larger.
|
||||
|
||||
## Shopify analytics
|
||||
|
||||
1. Visit https://[your-store-id].myshopify.com/shop.json
|
||||
2. Search for `shopId` and add it to the `NEXT_PUBLIC_SHOPIFY_SHOP_ID` in your `.env` file.
|
||||
|
||||
To test out Shopify analytics, in your localhost, you can use the following steps:
|
||||
|
||||
1. Install ngrok
|
||||
2. Setup custom domain in ngrok dashboard
|
||||
3. Expose your local development server (e.g., running on port 3000) with a command:
|
||||
|
||||
```bash
|
||||
ngrok http --domain=YOUR_NGROK_DOMAIN 3000
|
||||
```
|
||||
|
||||
## Running locally
|
||||
|
||||
You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js Commerce. It's recommended you use [Vercel Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) for this, but a `.env` file is all that is necessary.
|
||||
You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js Commerce. It's
|
||||
recommended you use [Vercel Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) for
|
||||
this, but a `.env` file is all that is necessary.
|
||||
|
||||
> Note: You should not commit your `.env` file or it will expose secrets that will allow others to control your Shopify store.
|
||||
> Note: You should not commit your `.env` file or it will expose secrets that will allow others to control your Shopify
|
||||
> store.
|
||||
|
||||
1. Install Vercel CLI: `npm i -g vercel`
|
||||
2. Link local instance with Vercel and GitHub accounts (creates `.vercel` directory): `vercel link`
|
||||
@ -69,8 +95,11 @@ Your app should now be running on [localhost:3000](http://localhost:3000/).
|
||||
1. Connect to the existing `commerce-shopify` project.
|
||||
1. Run `vc env pull` to get environment variables.
|
||||
1. Run `pnpm dev` to ensure everything is working correctly.
|
||||
|
||||
</details>
|
||||
|
||||
## Vercel, Next.js Commerce, and Shopify Integration Guide
|
||||
|
||||
You can use this comprehensive [integration guide](http://vercel.com/docs/integrations/shopify) with step-by-step instructions on how to configure Shopify as a headless CMS using Next.js Commerce as your headless Shopify storefront on Vercel.
|
||||
You can use this comprehensive [integration guide](http://vercel.com/docs/integrations/shopify) with step-by-step
|
||||
instructions on how to configure Shopify as a headless CMS using Next.js Commerce as your headless Shopify storefront on
|
||||
Vercel.
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Navbar from 'components/layout/navbar';
|
||||
import { GeistSans } from 'geist/font';
|
||||
import ShopifyAnalytics from 'components/layout/shopify-analytics';
|
||||
import { ensureStartsWith } from 'lib/utils';
|
||||
import { ReactNode, Suspense } from 'react';
|
||||
import './globals.css';
|
||||
@ -39,6 +40,7 @@ export default async function RootLayout({ children }: { children: ReactNode })
|
||||
<Suspense>
|
||||
<main>{children}</main>
|
||||
</Suspense>
|
||||
<ShopifyAnalytics />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
@ -4,10 +4,23 @@ import { TAGS } from 'lib/constants';
|
||||
import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/shopify';
|
||||
import { revalidateTag } from 'next/cache';
|
||||
import { cookies } from 'next/headers';
|
||||
import { ShopifyAnalyticsProduct } from '@shopify/hydrogen-react';
|
||||
import { productToAnalytics } from 'lib/utils';
|
||||
|
||||
export async function addItem(prevState: any, selectedVariantId: string | undefined) {
|
||||
type AddItemResponse = {
|
||||
cartId?: string;
|
||||
success: boolean;
|
||||
message?: string;
|
||||
products?: ShopifyAnalyticsProduct[];
|
||||
};
|
||||
|
||||
export async function addItem(
|
||||
prevState: any,
|
||||
selectedVariantId: string | undefined
|
||||
): Promise<AddItemResponse> {
|
||||
let cartId = cookies().get('cartId')?.value;
|
||||
let cart;
|
||||
const quantity = 1;
|
||||
|
||||
if (cartId) {
|
||||
cart = await getCart(cartId);
|
||||
@ -20,14 +33,20 @@ export async function addItem(prevState: any, selectedVariantId: string | undefi
|
||||
}
|
||||
|
||||
if (!selectedVariantId) {
|
||||
return 'Missing product variant ID';
|
||||
return { success: false, message: 'Missing product variant ID' };
|
||||
}
|
||||
|
||||
try {
|
||||
await addToCart(cartId, [{ merchandiseId: selectedVariantId, quantity: 1 }]);
|
||||
const response = await addToCart(cartId, [{ merchandiseId: selectedVariantId, quantity }]);
|
||||
revalidateTag(TAGS.cart);
|
||||
return {
|
||||
success: true,
|
||||
message: 'Item added to cart',
|
||||
cartId,
|
||||
products: productToAnalytics(response.lines, quantity, selectedVariantId)
|
||||
};
|
||||
} catch (e) {
|
||||
return 'Error adding item to cart';
|
||||
return { success: false, message: 'Error adding item to cart' };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ import LoadingDots from 'components/loading-dots';
|
||||
import { ProductVariant } from 'lib/shopify/types';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { useFormState, useFormStatus } from 'react-dom';
|
||||
import { useEffect } from 'react';
|
||||
import { useShopifyAnalytics } from 'lib/shopify/hooks/use-shopify-analytics';
|
||||
|
||||
function SubmitButton({
|
||||
availableForSale,
|
||||
@ -70,7 +72,8 @@ export function AddToCart({
|
||||
variants: ProductVariant[];
|
||||
availableForSale: boolean;
|
||||
}) {
|
||||
const [message, formAction] = useFormState(addItem, null);
|
||||
const { sendAddToCart } = useShopifyAnalytics();
|
||||
const [response, formAction] = useFormState(addItem, null);
|
||||
const searchParams = useSearchParams();
|
||||
const defaultVariantId = variants.length === 1 ? variants[0]?.id : undefined;
|
||||
const variant = variants.find((variant: ProductVariant) =>
|
||||
@ -81,12 +84,24 @@ export function AddToCart({
|
||||
const selectedVariantId = variant?.id || defaultVariantId;
|
||||
const actionWithVariant = formAction.bind(null, selectedVariantId);
|
||||
|
||||
useEffect(() => {
|
||||
if (response?.success && response.cartId) {
|
||||
sendAddToCart({
|
||||
cartId: response.cartId,
|
||||
products: response.products,
|
||||
totalValue: Number(response.products?.[0]?.price)
|
||||
});
|
||||
}
|
||||
}, [response?.success, response?.cartId, sendAddToCart, response?.products]);
|
||||
|
||||
return (
|
||||
<form action={actionWithVariant}>
|
||||
<SubmitButton availableForSale={availableForSale} selectedVariantId={selectedVariantId} />
|
||||
<p aria-live="polite" className="sr-only" role="status">
|
||||
{message}
|
||||
</p>
|
||||
{response?.message && (
|
||||
<p aria-live="polite" className="sr-only" role="status">
|
||||
{response.message}
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
13
components/layout/shopify-analytics.tsx
Normal file
13
components/layout/shopify-analytics.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { AnalyticsEventName } from '@shopify/hydrogen-react';
|
||||
import { useShopifyAnalytics } from 'lib/shopify/hooks/use-shopify-analytics';
|
||||
|
||||
export default function ShopifyAnalytics() {
|
||||
const { sendPageView, pathname } = useShopifyAnalytics();
|
||||
useEffect(() => {
|
||||
sendPageView(AnalyticsEventName.PAGE_VIEW);
|
||||
}, [pathname, sendPageView]);
|
||||
return null;
|
||||
}
|
@ -29,3 +29,8 @@ export const TAGS = {
|
||||
export const HIDDEN_PRODUCT_TAG = 'nextjs-frontend-hidden';
|
||||
export const DEFAULT_OPTION = 'Default Title';
|
||||
export const SHOPIFY_GRAPHQL_API_ENDPOINT = '/api/2023-01/graphql.json';
|
||||
|
||||
export const DEFAULT_CURRENCY = 'AED';
|
||||
|
||||
// use your logic to get language
|
||||
export const DEFAULT_LANGUAGE = 'EN';
|
||||
|
@ -37,6 +37,10 @@ const cartFragment = /* GraphQL */ `
|
||||
name
|
||||
value
|
||||
}
|
||||
price {
|
||||
amount
|
||||
currencyCode
|
||||
}
|
||||
product {
|
||||
...product
|
||||
}
|
||||
|
68
lib/shopify/hooks/use-shopify-analytics.ts
Normal file
68
lib/shopify/hooks/use-shopify-analytics.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { usePathname } from 'next/navigation';
|
||||
import {
|
||||
AnalyticsEventName,
|
||||
getClientBrowserParameters,
|
||||
sendShopifyAnalytics,
|
||||
ShopifyAnalyticsProduct,
|
||||
ShopifyPageViewPayload,
|
||||
ShopifySalesChannel,
|
||||
useShopifyCookies
|
||||
} from '@shopify/hydrogen-react';
|
||||
import { DEFAULT_CURRENCY, DEFAULT_LANGUAGE } from 'lib/constants';
|
||||
|
||||
const SHOP_ID = process.env.NEXT_PUBLIC_SHOPIFY_SHOP_ID!;
|
||||
|
||||
type SendPageViewPayload = {
|
||||
pageType?: string;
|
||||
products?: ShopifyAnalyticsProduct[];
|
||||
collectionHandle?: string;
|
||||
searchString?: string;
|
||||
totalValue?: number;
|
||||
cartId?: string;
|
||||
};
|
||||
|
||||
type SendAddToCartPayload = {
|
||||
cartId: string;
|
||||
products?: ShopifyAnalyticsProduct[];
|
||||
totalValue?: ShopifyPageViewPayload['totalValue'];
|
||||
};
|
||||
|
||||
export function useShopifyAnalytics() {
|
||||
const pathname = usePathname();
|
||||
// send page view event
|
||||
const sendPageView = (
|
||||
eventName: keyof typeof AnalyticsEventName,
|
||||
payload?: SendPageViewPayload
|
||||
) =>
|
||||
sendShopifyAnalytics({
|
||||
eventName,
|
||||
payload: {
|
||||
...getClientBrowserParameters(),
|
||||
hasUserConsent: true,
|
||||
shopifySalesChannel: ShopifySalesChannel.headless,
|
||||
shopId: `gid://shopify/Shop/${SHOP_ID}`,
|
||||
currency: DEFAULT_CURRENCY,
|
||||
acceptedLanguage: DEFAULT_LANGUAGE,
|
||||
...payload
|
||||
}
|
||||
});
|
||||
|
||||
// send add to cart event
|
||||
const sendAddToCart = ({ cartId, totalValue, products }: SendAddToCartPayload) =>
|
||||
sendPageView(AnalyticsEventName.ADD_TO_CART, {
|
||||
cartId,
|
||||
totalValue,
|
||||
products
|
||||
});
|
||||
|
||||
// setup cookies for shopify analytics & enable user consent
|
||||
useShopifyCookies({
|
||||
hasUserConsent: true
|
||||
});
|
||||
|
||||
return {
|
||||
sendPageView,
|
||||
sendAddToCart,
|
||||
pathname
|
||||
};
|
||||
}
|
@ -2,7 +2,7 @@ import { HIDDEN_PRODUCT_TAG, SHOPIFY_GRAPHQL_API_ENDPOINT, TAGS } from 'lib/cons
|
||||
import { isShopifyError } from 'lib/type-guards';
|
||||
import { ensureStartsWith } from 'lib/utils';
|
||||
import { revalidateTag } from 'next/cache';
|
||||
import { headers } from 'next/headers';
|
||||
import { cookies, headers } from 'next/headers';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import {
|
||||
addToCartMutation,
|
||||
@ -214,12 +214,19 @@ export async function addToCart(
|
||||
cartId: string,
|
||||
lines: { merchandiseId: string; quantity: number }[]
|
||||
): Promise<Cart> {
|
||||
// get shopify cookies
|
||||
const shopifyY = cookies()?.get('_shopify_y')?.value;
|
||||
const shopifyS = cookies()?.get('_shopify_s')?.value;
|
||||
|
||||
const res = await shopifyFetch<ShopifyAddToCartOperation>({
|
||||
query: addToCartMutation,
|
||||
variables: {
|
||||
cartId,
|
||||
lines
|
||||
},
|
||||
headers: {
|
||||
...(shopifyY && shopifyS && { cookie: `_shopify_y=${shopifyY}; _shopify_s=${shopifyS};` })
|
||||
},
|
||||
cache: 'no-store'
|
||||
});
|
||||
return reshapeCart(res.body.data.cartLinesAdd.cart);
|
||||
|
@ -21,6 +21,7 @@ export type CartItem = {
|
||||
merchandise: {
|
||||
id: string;
|
||||
title: string;
|
||||
price: Money;
|
||||
selectedOptions: {
|
||||
name: string;
|
||||
value: string;
|
||||
|
29
lib/utils.ts
29
lib/utils.ts
@ -1,4 +1,6 @@
|
||||
import { ReadonlyURLSearchParams } from 'next/navigation';
|
||||
import { Cart } from './shopify/types';
|
||||
import { ShopifyAnalyticsProduct } from '@shopify/hydrogen-react';
|
||||
|
||||
export const createUrl = (pathname: string, params: URLSearchParams | ReadonlyURLSearchParams) => {
|
||||
const paramsString = params.toString();
|
||||
@ -37,3 +39,30 @@ export const validateEnvironmentVariables = () => {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This function takes a cart and a quantity and returns an array of ShopifyAnalyticsProduct objects.
|
||||
* */
|
||||
export const productToAnalytics = (
|
||||
cartItems: Cart['lines'],
|
||||
quantity: number,
|
||||
variantId: string
|
||||
) => {
|
||||
const line = cartItems.find((line) => line.merchandise.id === variantId);
|
||||
if (!line) return;
|
||||
|
||||
const { merchandise } = line;
|
||||
|
||||
if (!merchandise) return;
|
||||
|
||||
return [
|
||||
{
|
||||
productGid: merchandise?.product.id,
|
||||
variantGid: variantId,
|
||||
name: merchandise?.product.title,
|
||||
variantName: merchandise?.title,
|
||||
price: merchandise?.price.amount,
|
||||
quantity
|
||||
} as ShopifyAnalyticsProduct
|
||||
];
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.7.18",
|
||||
"@heroicons/react": "^2.1.3",
|
||||
"@shopify/hydrogen-react": "^2024.1.1",
|
||||
"clsx": "^2.1.0",
|
||||
"geist": "^1.3.0",
|
||||
"next": "14.1.4",
|
||||
|
141
pnpm-lock.yaml
generated
141
pnpm-lock.yaml
generated
@ -11,6 +11,9 @@ dependencies:
|
||||
'@heroicons/react':
|
||||
specifier: ^2.1.3
|
||||
version: 2.1.3(react@18.2.0)
|
||||
'@shopify/hydrogen-react':
|
||||
specifier: ^2024.1.1
|
||||
version: 2024.1.1(@types/react@18.2.72)(react-dom@18.2.0)(react@18.2.0)
|
||||
clsx:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
@ -159,6 +162,14 @@ packages:
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dev: true
|
||||
|
||||
/@google/model-viewer@1.12.1:
|
||||
resolution: {integrity: sha512-GOf/By81rbxSmwWRVxBtlY5b3050msJ+BDWqonPj7M0/I7rNS/vVNjbLxTofbGjZObS3n0ELHj8TZ47UtkZbtg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
dependencies:
|
||||
lit: 2.8.0
|
||||
three: 0.139.2
|
||||
dev: false
|
||||
|
||||
/@headlessui/react@1.7.18(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-4i5DOrzwN4qSgNsL4Si61VMkUcWbcSKueUV7sFhpHzQcSShdlHENE5+QBntMSRvHt8NyoFO2AGG8si9lq+w4zQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -242,6 +253,16 @@ packages:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
dev: true
|
||||
|
||||
/@lit-labs/ssr-dom-shim@1.2.0:
|
||||
resolution: {integrity: sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==}
|
||||
dev: false
|
||||
|
||||
/@lit/reactive-element@1.6.3:
|
||||
resolution: {integrity: sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==}
|
||||
dependencies:
|
||||
'@lit-labs/ssr-dom-shim': 1.2.0
|
||||
dev: false
|
||||
|
||||
/@next/env@14.1.4:
|
||||
resolution: {integrity: sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==}
|
||||
dev: false
|
||||
@ -365,6 +386,26 @@ packages:
|
||||
resolution: {integrity: sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==}
|
||||
dev: true
|
||||
|
||||
/@shopify/hydrogen-react@2024.1.1(@types/react@18.2.72)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-3ZDTUZPauXyV6TTxSjsEd0KEybT0jDpaEaB2tPtpjq783rJ1xD+wS9sWqqaKhAY2EUngg03muZiiuBeZIbR4Fw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
dependencies:
|
||||
'@google/model-viewer': 1.12.1
|
||||
'@xstate/fsm': 2.1.0
|
||||
'@xstate/react': 3.2.2(@types/react@18.2.72)(@xstate/fsm@2.1.0)(react@18.2.0)
|
||||
graphql: 16.8.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
type-fest: 4.14.0
|
||||
worktop: 0.7.3
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
- xstate
|
||||
dev: false
|
||||
|
||||
/@swc/helpers@0.5.2:
|
||||
resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==}
|
||||
dependencies:
|
||||
@ -422,7 +463,6 @@ packages:
|
||||
|
||||
/@types/prop-types@15.7.12:
|
||||
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
|
||||
dev: true
|
||||
|
||||
/@types/react-dom@18.2.22:
|
||||
resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==}
|
||||
@ -435,7 +475,10 @@ packages:
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.12
|
||||
csstype: 3.1.3
|
||||
dev: true
|
||||
|
||||
/@types/trusted-types@2.0.7:
|
||||
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
||||
dev: false
|
||||
|
||||
/@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3):
|
||||
resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==}
|
||||
@ -510,6 +553,30 @@ packages:
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
|
||||
/@xstate/fsm@2.1.0:
|
||||
resolution: {integrity: sha512-oJlc0iD0qZvAM7If/KlyJyqUt7wVI8ocpsnlWzAPl97evguPbd+oJbRM9R4A1vYJffYH96+Bx44nLDE6qS8jQg==}
|
||||
dev: false
|
||||
|
||||
/@xstate/react@3.2.2(@types/react@18.2.72)(@xstate/fsm@2.1.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-feghXWLedyq8JeL13yda3XnHPZKwYDN5HPBLykpLeuNpr9178tQd2/3d0NrH6gSd0sG5mLuLeuD+ck830fgzLQ==}
|
||||
peerDependencies:
|
||||
'@xstate/fsm': ^2.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
xstate: ^4.37.2
|
||||
peerDependenciesMeta:
|
||||
'@xstate/fsm':
|
||||
optional: true
|
||||
xstate:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@xstate/fsm': 2.1.0
|
||||
react: 18.2.0
|
||||
use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.72)(react@18.2.0)
|
||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
dev: false
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@8.11.3):
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
peerDependencies:
|
||||
@ -944,7 +1011,6 @@ packages:
|
||||
|
||||
/csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
dev: true
|
||||
|
||||
/damerau-levenshtein@1.0.8:
|
||||
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
|
||||
@ -1792,6 +1858,11 @@ packages:
|
||||
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
||||
dev: true
|
||||
|
||||
/graphql@16.8.1:
|
||||
resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==}
|
||||
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
|
||||
dev: false
|
||||
|
||||
/has-bigints@1.0.2:
|
||||
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
|
||||
dev: true
|
||||
@ -2255,6 +2326,28 @@ packages:
|
||||
wrap-ansi: 9.0.0
|
||||
dev: true
|
||||
|
||||
/lit-element@3.3.3:
|
||||
resolution: {integrity: sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==}
|
||||
dependencies:
|
||||
'@lit-labs/ssr-dom-shim': 1.2.0
|
||||
'@lit/reactive-element': 1.6.3
|
||||
lit-html: 2.8.0
|
||||
dev: false
|
||||
|
||||
/lit-html@2.8.0:
|
||||
resolution: {integrity: sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==}
|
||||
dependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
dev: false
|
||||
|
||||
/lit@2.8.0:
|
||||
resolution: {integrity: sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==}
|
||||
dependencies:
|
||||
'@lit/reactive-element': 1.6.3
|
||||
lit-element: 3.3.3
|
||||
lit-html: 2.8.0
|
||||
dev: false
|
||||
|
||||
/locate-path@5.0.0:
|
||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||
engines: {node: '>=8'}
|
||||
@ -2941,6 +3034,11 @@ packages:
|
||||
set-function-name: 2.0.2
|
||||
dev: true
|
||||
|
||||
/regexparam@2.0.2:
|
||||
resolution: {integrity: sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/regjsparser@0.10.0:
|
||||
resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==}
|
||||
hasBin: true
|
||||
@ -3369,6 +3467,10 @@ packages:
|
||||
any-promise: 1.3.0
|
||||
dev: true
|
||||
|
||||
/three@0.139.2:
|
||||
resolution: {integrity: sha512-gV7q7QY8rogu7HLFZR9cWnOQAUedUhu2WXAnpr2kdXZP9YDKsG/0ychwQvWkZN5PlNw9mv5MoCTin6zNTXoONg==}
|
||||
dev: false
|
||||
|
||||
/to-regex-range@5.0.1:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
@ -3424,6 +3526,11 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/type-fest@4.14.0:
|
||||
resolution: {integrity: sha512-on5/Cw89wwqGZQu+yWO0gGMGu8VNxsaW9SB2HE8yJjllEk7IDTwnSN1dUVldYILhYPN5HzD7WAaw2cc/jBfn0Q==}
|
||||
engines: {node: '>=16'}
|
||||
dev: false
|
||||
|
||||
/typed-array-buffer@1.0.2:
|
||||
resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -3504,6 +3611,27 @@ packages:
|
||||
punycode: 2.3.1
|
||||
dev: true
|
||||
|
||||
/use-isomorphic-layout-effect@1.1.2(@types/react@18.2.72)(react@18.2.0):
|
||||
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/react': 18.2.72
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/use-sync-external-store@1.2.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
dev: true
|
||||
@ -3572,6 +3700,13 @@ packages:
|
||||
isexe: 2.0.0
|
||||
dev: true
|
||||
|
||||
/worktop@0.7.3:
|
||||
resolution: {integrity: sha512-WBHP1hk8pLP7ahAw13fugDWcO0SUAOiCD6DHT/bfLWoCIA/PL9u7GKdudT2nGZ8EGR1APbGCAI6ZzKG1+X+PnQ==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
regexparam: 2.0.2
|
||||
dev: false
|
||||
|
||||
/wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
Loading…
x
Reference in New Issue
Block a user