This commit is contained in:
Kristian Duda 2024-06-28 07:42:33 +02:00
parent 7fd9ad8a8c
commit b94e46d796
8 changed files with 443 additions and 61 deletions

View File

@ -2,6 +2,8 @@ COMPANY_NAME="Vercel Inc."
TWITTER_CREATOR="@vercel" TWITTER_CREATOR="@vercel"
TWITTER_SITE="https://nextjs.org/commerce" TWITTER_SITE="https://nextjs.org/commerce"
SITE_NAME="Next.js Commerce" SITE_NAME="Next.js Commerce"
SHOPIFY_REVALIDATION_SECRET="" # SHOPIFY_REVALIDATION_SECRET=""
SHOPIFY_STOREFRONT_ACCESS_TOKEN="" # SHOPIFY_STOREFRONT_ACCESS_TOKEN=""
SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com" # SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com"
CMS_URL="http://localhost:3000"

35
lib/shopify/ajax.ts Normal file
View File

@ -0,0 +1,35 @@
interface ErrorMessage {
message: string;
}
export class AjaxError extends Error {
statusCode: number;
errors: ErrorMessage[];
constructor(statusCode: number, message: string, errors: ErrorMessage[] = []) {
super(message);
this.errors = errors;
this.statusCode = statusCode;
}
}
type AjaxMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
export const ajax = async <T>(method: AjaxMethod, url: string, data?: object): Promise<T> => {
const response = await fetch(url, {
method,
credentials: 'include',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: data ? JSON.stringify(data) : undefined
});
const body = await response.json();
if (response.ok) {
return body as T;
}
throw new AjaxError(response.status, body.message ?? response.statusText, body.errors);
};

View File

@ -1,4 +1,6 @@
import { HIDDEN_PRODUCT_TAG, SHOPIFY_GRAPHQL_API_ENDPOINT, TAGS } from 'lib/constants'; import { HIDDEN_PRODUCT_TAG, SHOPIFY_GRAPHQL_API_ENDPOINT, TAGS } from 'lib/constants';
import { find } from 'lib/shopify/payload';
import { Media, Option, Product } from 'lib/shopify/payload-types';
import { isShopifyError } from 'lib/type-guards'; import { isShopifyError } from 'lib/type-guards';
import { ensureStartsWith } from 'lib/utils'; import { ensureStartsWith } from 'lib/utils';
import { revalidateTag } from 'next/cache'; import { revalidateTag } from 'next/cache';
@ -11,12 +13,7 @@ import {
removeFromCartMutation removeFromCartMutation
} from './mutations/cart'; } from './mutations/cart';
import { getCartQuery } from './queries/cart'; import { getCartQuery } from './queries/cart';
import { import { getCollectionQuery, getCollectionsQuery } from './queries/collection';
getCollectionProductsQuery,
getCollectionQuery,
getCollectionsQuery
} from './queries/collection';
import { getMenuQuery } from './queries/menu';
import { getPageQuery, getPagesQuery } from './queries/page'; import { getPageQuery, getPagesQuery } from './queries/page';
import { import {
getProductQuery, getProductQuery,
@ -27,19 +24,19 @@ import {
Cart, Cart,
Collection, Collection,
Connection, Connection,
Product as ExProduct,
Image, Image,
Menu, Menu,
Money,
Page, Page,
Product, ProductOption,
ShopifyAddToCartOperation, ShopifyAddToCartOperation,
ShopifyCart, ShopifyCart,
ShopifyCartOperation, ShopifyCartOperation,
ShopifyCollection, ShopifyCollection,
ShopifyCollectionOperation, ShopifyCollectionOperation,
ShopifyCollectionProductsOperation,
ShopifyCollectionsOperation, ShopifyCollectionsOperation,
ShopifyCreateCartOperation, ShopifyCreateCartOperation,
ShopifyMenuOperation,
ShopifyPageOperation, ShopifyPageOperation,
ShopifyPagesOperation, ShopifyPagesOperation,
ShopifyProduct, ShopifyProduct,
@ -282,6 +279,62 @@ export async function getCollection(handle: string): Promise<Collection | undefi
return reshapeCollection(res.body.data.collection); return reshapeCollection(res.body.data.collection);
} }
const reshapeImage = (media: Media): Image => {
return {
url: media.url!,
altText: media.alt
};
};
type Price = {
amount: number;
currencyCode: string;
};
const reshapePrice = (price: Price): Money => {
return {
amount: (price.amount / 100).toString(),
currencyCode: price.currencyCode
};
};
const reshapeP = (product: Product): ExProduct => {
const options: ProductOption[] = [];
const map = new Map();
product.variants.forEach((variant) => {
variant.selectedOptions?.forEach((selectedOption) => {
const option = selectedOption.option as Option;
map.set(option.id, option.values);
});
});
// console.log(map);
return {
id: product.id,
handle: product.id,
availableForSale: !product.disabled,
title: product.title,
description: product.description,
descriptionHtml: product.description,
options,
priceRange: {
maxVariantPrice: reshapePrice(product.variants[0]?.price!),
minVariantPrice: reshapePrice(product.variants[0]?.price!)
},
featuredImage: {} as any,
images: [],
seo: {
title: product.title,
description: product.description
},
// tags: product.tags ?? [],
updatedAt: product.updatedAt,
createdAt: product.createdAt
};
};
export async function getCollectionProducts({ export async function getCollectionProducts({
collection, collection,
reverse, reverse,
@ -290,23 +343,20 @@ export async function getCollectionProducts({
collection: string; collection: string;
reverse?: boolean; reverse?: boolean;
sortKey?: string; sortKey?: string;
}): Promise<Product[]> { }): Promise<ExProduct[]> {
const res = await shopifyFetch<ShopifyCollectionProductsOperation>({ const m = await find<Product>('products', {
query: getCollectionProductsQuery, where: {
tags: [TAGS.collections, TAGS.products], title: {
variables: { equals: 'test'
handle: collection, }
reverse,
sortKey: sortKey === 'CREATED_AT' ? 'CREATED' : sortKey
} }
}); });
if (!res.body.data.collection) { const products: ExProduct[] = m.docs.map(reshapeP);
console.log(`No collection found for \`${collection}\``);
return [];
}
return reshapeProducts(removeEdgesAndNodes(res.body.data.collection.products)); console.log(products);
return products;
} }
export async function getCollections(): Promise<Collection[]> { export async function getCollections(): Promise<Collection[]> {
@ -338,20 +388,21 @@ export async function getCollections(): Promise<Collection[]> {
} }
export async function getMenu(handle: string): Promise<Menu[]> { export async function getMenu(handle: string): Promise<Menu[]> {
const res = await shopifyFetch<ShopifyMenuOperation>({ return [];
query: getMenuQuery, // const res = await shopifyFetch<ShopifyMenuOperation>({
tags: [TAGS.collections], // query: getMenuQuery,
variables: { // tags: [TAGS.collections],
handle // variables: {
} // handle
}); // }
// });
return ( // return (
res.body?.data?.menu?.items.map((item: { title: string; url: string }) => ({ // res.body?.data?.menu?.items.map((item: { title: string; url: string }) => ({
title: item.title, // title: item.title,
path: item.url.replace(domain, '').replace('/collections', '/search').replace('/pages', '') // path: item.url.replace(domain, '').replace('/collections', '/search').replace('/pages', '')
})) || [] // })) || []
); // );
} }
export async function getPage(handle: string): Promise<Page> { export async function getPage(handle: string): Promise<Page> {
@ -373,7 +424,7 @@ export async function getPages(): Promise<Page[]> {
return removeEdgesAndNodes(res.body.data.pages); return removeEdgesAndNodes(res.body.data.pages);
} }
export async function getProduct(handle: string): Promise<Product | undefined> { export async function getProduct(handle: string): Promise<ExProduct | undefined> {
const res = await shopifyFetch<ShopifyProductOperation>({ const res = await shopifyFetch<ShopifyProductOperation>({
query: getProductQuery, query: getProductQuery,
tags: [TAGS.products], tags: [TAGS.products],
@ -385,7 +436,7 @@ export async function getProduct(handle: string): Promise<Product | undefined> {
return reshapeProduct(res.body.data.product, false); return reshapeProduct(res.body.data.product, false);
} }
export async function getProductRecommendations(productId: string): Promise<Product[]> { export async function getProductRecommendations(productId: string): Promise<ExProduct[]> {
const res = await shopifyFetch<ShopifyProductRecommendationsOperation>({ const res = await shopifyFetch<ShopifyProductRecommendationsOperation>({
query: getProductRecommendationsQuery, query: getProductRecommendationsQuery,
tags: [TAGS.products], tags: [TAGS.products],
@ -405,7 +456,7 @@ export async function getProducts({
query?: string; query?: string;
reverse?: boolean; reverse?: boolean;
sortKey?: string; sortKey?: string;
}): Promise<Product[]> { }): Promise<ExProduct[]> {
const res = await shopifyFetch<ShopifyProductsOperation>({ const res = await shopifyFetch<ShopifyProductsOperation>({
query: getProductsQuery, query: getProductsQuery,
tags: [TAGS.products], tags: [TAGS.products],

View File

@ -0,0 +1,228 @@
/* tslint:disable */
/* eslint-disable */
/**
* This file was automatically generated by Payload.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {
collections: {
posts: Post;
tags: Tag;
media: Media;
users: User;
options: Option;
products: Product;
carts: Cart;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
globals: {};
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts".
*/
export interface Post {
id: string;
title: string;
summary?: string | null;
content?: {
root: {
type: string;
children: {
type: string;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
} | null;
tags?: (string | Tag)[] | null;
publishedAt?: string | null;
authors?: (string | User)[] | null;
populatedAuthors?:
| {
id?: string | null;
name?: string | null;
}[]
| null;
slug?: string | null;
meta?: {
title?: string | null;
description?: string | null;
image?: string | Media | null;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "tags".
*/
export interface Tag {
id: string;
name: string;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
name?: string | null;
roles?: ('admin' | 'user')[] | null;
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string | null;
resetPasswordExpiration?: string | null;
salt?: string | null;
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
password: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media".
*/
export interface Media {
id: string;
alt: string;
caption?: {
root: {
type: string;
children: {
type: string;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
} | null;
updatedAt: string;
createdAt: string;
url?: string | null;
filename?: string | null;
mimeType?: string | null;
filesize?: number | null;
width?: number | null;
height?: number | null;
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "options".
*/
export interface Option {
id: string;
name: string;
values: {
value: string;
label: string;
id?: string | null;
}[];
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "products".
*/
export interface Product {
id: string;
title: string;
disabled?: boolean | null;
description: string;
media: string | Media;
variants: {
price: {
amount: number;
currencyCode: 'eur';
stripePriceID?: string | null;
};
selectedOptions?:
| {
option: string | Option;
value: string;
id?: string | null;
}[]
| null;
id?: string | null;
}[];
tags?: (string | Tag)[] | null;
stripeProductID?: string | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "carts".
*/
export interface Cart {
id: string;
name: string;
totalAmount?: number | null;
user?: (string | null) | User;
lines?:
| {
product: string | Product;
variant: string;
quantity: number;
id?: string | null;
}[]
| null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences".
*/
export interface PayloadPreference {
id: string;
user: {
relationTo: 'users';
value: string | User;
};
key?: string | null;
value?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations".
*/
export interface PayloadMigration {
id: string;
name?: string | null;
batch?: number | null;
updatedAt: string;
createdAt: string;
}
declare module 'payload' {
export interface GeneratedTypes extends Config {}
}

61
lib/shopify/payload.ts Normal file
View File

@ -0,0 +1,61 @@
import { ajax } from 'lib/shopify/ajax';
import { Config } from 'lib/shopify/payload-types';
import qs from 'qs';
type Collection = keyof Config['collections'];
const OPERATORS = [
'equals',
'contains',
'not_equals',
'in',
'all',
'not_in',
'exists',
'greater_than',
'greater_than_equal',
'less_than',
'less_than_equal',
'like',
'within',
'intersects',
'near'
] as const;
type Operator = (typeof OPERATORS)[number];
type WhereField = {
[key in Operator]?: unknown;
};
type Where = {
[key: string]: Where[] | WhereField;
and?: Where[];
or?: Where[];
};
export type PaginatedDocs<T> = {
docs: T[];
hasNextPage: boolean;
hasPrevPage: boolean;
limit: number;
nextPage?: null | number;
page?: number;
pagingCounter: number;
prevPage?: null | number;
totalDocs: number;
totalPages: number;
};
type FindParams = {
where?: Where;
depth?: number;
sort?: string;
page?: number;
limit?: number;
};
export const find = <T>(collection: string, params: FindParams) => {
const query = qs.stringify(params, { addQueryPrefix: true });
const url = `${process.env.CMS_URL}/api/${collection}${query}`;
return ajax<PaginatedDocs<T>>('GET', url);
};

View File

@ -36,8 +36,8 @@ export type Collection = ShopifyCollection & {
export type Image = { export type Image = {
url: string; url: string;
altText: string; altText: string;
width: number; width?: number;
height: number; height?: number;
}; };
export type Menu = { export type Menu = {

View File

@ -27,6 +27,7 @@
"clsx": "^2.1.0", "clsx": "^2.1.0",
"geist": "^1.3.0", "geist": "^1.3.0",
"next": "14.2.2", "next": "14.2.2",
"qs": "^6.12.1",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0" "react-dom": "18.2.0"
}, },
@ -34,6 +35,7 @@
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/typography": "^0.5.12", "@tailwindcss/typography": "^0.5.12",
"@types/node": "20.12.7", "@types/node": "20.12.7",
"@types/qs": "^6.9.15",
"@types/react": "18.2.79", "@types/react": "18.2.79",
"@types/react-dom": "18.2.25", "@types/react-dom": "18.2.25",
"@vercel/git-hooks": "^1.0.0", "@vercel/git-hooks": "^1.0.0",

39
pnpm-lock.yaml generated
View File

@ -1,9 +1,5 @@
lockfileVersion: '6.0' lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies: dependencies:
'@headlessui/react': '@headlessui/react':
specifier: ^1.7.19 specifier: ^1.7.19
@ -20,6 +16,9 @@ dependencies:
next: next:
specifier: 14.2.2 specifier: 14.2.2
version: 14.2.2(react-dom@18.2.0)(react@18.2.0) version: 14.2.2(react-dom@18.2.0)(react@18.2.0)
qs:
specifier: ^6.12.1
version: 6.12.1
react: react:
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0 version: 18.2.0
@ -37,6 +36,9 @@ devDependencies:
'@types/node': '@types/node':
specifier: 20.12.7 specifier: 20.12.7
version: 20.12.7 version: 20.12.7
'@types/qs':
specifier: ^6.9.15
version: 6.9.15
'@types/react': '@types/react':
specifier: 18.2.79 specifier: 18.2.79
version: 18.2.79 version: 18.2.79
@ -429,6 +431,10 @@ packages:
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
dev: true dev: true
/@types/qs@6.9.15:
resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==}
dev: true
/@types/react-dom@18.2.25: /@types/react-dom@18.2.25:
resolution: {integrity: sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==} resolution: {integrity: sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==}
dependencies: dependencies:
@ -799,7 +805,6 @@ packages:
function-bind: 1.1.2 function-bind: 1.1.2
get-intrinsic: 1.2.4 get-intrinsic: 1.2.4
set-function-length: 1.2.2 set-function-length: 1.2.2
dev: true
/callsites@3.1.0: /callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
@ -1016,7 +1021,6 @@ packages:
es-define-property: 1.0.0 es-define-property: 1.0.0
es-errors: 1.3.0 es-errors: 1.3.0
gopd: 1.0.1 gopd: 1.0.1
dev: true
/define-properties@1.2.1: /define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
@ -1152,12 +1156,10 @@ packages:
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dependencies: dependencies:
get-intrinsic: 1.2.4 get-intrinsic: 1.2.4
dev: true
/es-errors@1.3.0: /es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dev: true
/es-iterator-helpers@1.0.18: /es-iterator-helpers@1.0.18:
resolution: {integrity: sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==} resolution: {integrity: sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==}
@ -1661,7 +1663,6 @@ packages:
/function-bind@1.1.2: /function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
dev: true
/function.prototype.name@1.1.6: /function.prototype.name@1.1.6:
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
@ -1699,7 +1700,6 @@ packages:
has-proto: 1.0.3 has-proto: 1.0.3
has-symbols: 1.0.3 has-symbols: 1.0.3
hasown: 2.0.2 hasown: 2.0.2
dev: true
/get-stream@8.0.1: /get-stream@8.0.1:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
@ -1800,7 +1800,6 @@ packages:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies: dependencies:
get-intrinsic: 1.2.4 get-intrinsic: 1.2.4
dev: true
/graceful-fs@4.2.11: /graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@ -1827,17 +1826,14 @@ packages:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
dependencies: dependencies:
es-define-property: 1.0.0 es-define-property: 1.0.0
dev: true
/has-proto@1.0.3: /has-proto@1.0.3:
resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dev: true
/has-symbols@1.0.3: /has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dev: true
/has-tostringtag@1.0.2: /has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
@ -1851,7 +1847,6 @@ packages:
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dependencies: dependencies:
function-bind: 1.1.2 function-bind: 1.1.2
dev: true
/hosted-git-info@2.8.9: /hosted-git-info@2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
@ -2497,7 +2492,6 @@ packages:
/object-inspect@1.13.1: /object-inspect@1.13.1:
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
dev: true
/object-keys@1.1.1: /object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
@ -2879,6 +2873,13 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true dev: true
/qs@6.12.1:
resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==}
engines: {node: '>=0.6'}
dependencies:
side-channel: 1.0.6
dev: false
/queue-microtask@1.2.3: /queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true dev: true
@ -3085,7 +3086,6 @@ packages:
get-intrinsic: 1.2.4 get-intrinsic: 1.2.4
gopd: 1.0.1 gopd: 1.0.1
has-property-descriptors: 1.0.2 has-property-descriptors: 1.0.2
dev: true
/set-function-name@2.0.2: /set-function-name@2.0.2:
resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
@ -3117,7 +3117,6 @@ packages:
es-errors: 1.3.0 es-errors: 1.3.0
get-intrinsic: 1.2.4 get-intrinsic: 1.2.4
object-inspect: 1.13.1 object-inspect: 1.13.1
dev: true
/signal-exit@3.0.7: /signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
@ -3649,3 +3648,7 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true dev: true
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false