Cache query cursors for the product feed and support s3 (#478)
* Cache query cursors for the product feed * Fix missing first page of products * Add S3 upload * Explain sze limit on multipart upload * Change the name of function * Update the dependencies * Revert api response size override * Fix multi part upload * Remove duplicated code * Add channel name to the file URL
This commit is contained in:
parent
4801803ea0
commit
238f2b5d01
22 changed files with 1497 additions and 38 deletions
|
@ -16,6 +16,7 @@
|
|||
"schemaVersion": "3.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.332.0",
|
||||
"@hookform/resolvers": "^2.9.10",
|
||||
"@material-ui/core": "^4.12.4",
|
||||
"@material-ui/icons": "^4.11.3",
|
||||
|
|
|
@ -7,13 +7,16 @@ import {
|
|||
GoogleFeedProductVariantFragment,
|
||||
} from "../../../generated/graphql";
|
||||
|
||||
const getCursors = async ({ client, channel }: { client: Client; channel: string }) => {
|
||||
export const getCursors = async ({ client, channel }: { client: Client; channel: string }) => {
|
||||
const logger = createLogger({ saleorApiUrl: url, channel, fn: "getCursors" });
|
||||
|
||||
logger.debug(`Fetching cursors for channel ${channel}`);
|
||||
|
||||
let result = await client
|
||||
.query(FetchProductCursorsDocument, { channel: channel as string, first: 100 })
|
||||
.toPromise();
|
||||
|
||||
// First page is queried without the `after` param, so we start an array with `undefined`
|
||||
const cursors: Array<string | undefined> = [undefined];
|
||||
const cursors: Array<string> = [];
|
||||
|
||||
while (result.data?.productVariants?.pageInfo.hasNextPage) {
|
||||
result = await client
|
||||
|
@ -44,6 +47,8 @@ const fetchVariants = async ({
|
|||
}): Promise<GoogleFeedProductVariantFragment[]> => {
|
||||
const logger = createLogger({ saleorApiUrl: url, channel, fn: "fetchVariants" });
|
||||
|
||||
logger.debug(`Fetching variants for channel ${channel} with cursor ${after}`);
|
||||
|
||||
const result = await client
|
||||
.query(FetchProductDataForFeedDocument, {
|
||||
channel: channel as string,
|
||||
|
@ -63,16 +68,19 @@ const fetchVariants = async ({
|
|||
interface FetchProductDataArgs {
|
||||
client: Client;
|
||||
channel: string;
|
||||
cursors?: Array<string>;
|
||||
}
|
||||
|
||||
export const fetchProductData = async ({ client, channel }: FetchProductDataArgs) => {
|
||||
export const fetchProductData = async ({ client, channel, cursors }: FetchProductDataArgs) => {
|
||||
const logger = createLogger({ saleorApiUrl: url, channel, route: "Google Product Feed" });
|
||||
|
||||
const cursors = await getCursors({ client, channel });
|
||||
const cachedCursors = cursors || (await getCursors({ client, channel }));
|
||||
|
||||
logger.debug(`Query generated ${cursors.length} cursors`);
|
||||
const pageCursors = [undefined, ...cachedCursors];
|
||||
|
||||
const promises = cursors.map((cursor) => fetchVariants({ client, after: cursor, channel }));
|
||||
logger.debug(`Query generated ${pageCursors.length} cursors`);
|
||||
|
||||
const promises = pageCursors.map((cursor) => fetchVariants({ client, after: cursor, channel }));
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
|
||||
|
|
|
@ -29,5 +29,6 @@ export const getGoogleFeedSettings = async ({ authData, channel }: GetGoogleFeed
|
|||
return {
|
||||
storefrontUrl,
|
||||
productStorefrontUrl,
|
||||
s3BucketConfiguration: configuration.s3BucketConfiguration,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
FetchAppDetailsDocument,
|
||||
FetchAppDetailsQuery,
|
||||
UpdateAppMetadataDocument,
|
||||
} from "../../../generated/graphql";
|
||||
} from "../../generated/graphql";
|
||||
|
||||
gql`
|
||||
mutation UpdateAppMetadata($id: ID!, $input: [MetadataInput!]!) {
|
|
@ -5,6 +5,11 @@ const getDefaultEmptyUrlConfiguration = (): SellerShopConfig["urlConfiguration"]
|
|||
productStorefrontUrl: "",
|
||||
});
|
||||
|
||||
const getDefaultEmptyPerChannelConfiguration = (): SellerShopConfig => ({
|
||||
urlConfiguration: getDefaultEmptyUrlConfiguration(),
|
||||
s3BucketConfiguration: undefined, //getDefaultEmptyS3BucketConfiguration(),
|
||||
});
|
||||
|
||||
const getChannelUrlConfiguration =
|
||||
(appConfig: AppConfig | null | undefined) => (channelSlug: string) => {
|
||||
try {
|
||||
|
@ -20,15 +25,38 @@ const setChannelUrlConfiguration =
|
|||
(urlConfiguration: SellerShopConfig["urlConfiguration"]) => {
|
||||
const appConfigNormalized = structuredClone(appConfig) ?? { shopConfigPerChannel: {} };
|
||||
|
||||
appConfigNormalized.shopConfigPerChannel[channelSlug] ??= {
|
||||
urlConfiguration: getDefaultEmptyUrlConfiguration(),
|
||||
};
|
||||
appConfigNormalized.shopConfigPerChannel[channelSlug] ??=
|
||||
getDefaultEmptyPerChannelConfiguration();
|
||||
|
||||
appConfigNormalized.shopConfigPerChannel[channelSlug].urlConfiguration = urlConfiguration;
|
||||
|
||||
return appConfigNormalized;
|
||||
};
|
||||
|
||||
const getChannelS3BucketConfiguration =
|
||||
(appConfig: AppConfig | null | undefined) => (channelSlug: string) => {
|
||||
try {
|
||||
return appConfig?.shopConfigPerChannel[channelSlug].s3BucketConfiguration ?? null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const setChannelS3BucketConfiguration =
|
||||
(appConfig: AppConfig | null | undefined) =>
|
||||
(channelSlug: string) =>
|
||||
(s3BucketConfiguration: SellerShopConfig["s3BucketConfiguration"]) => {
|
||||
const appConfigNormalized = structuredClone(appConfig) ?? { shopConfigPerChannel: {} };
|
||||
|
||||
appConfigNormalized.shopConfigPerChannel[channelSlug].s3BucketConfiguration =
|
||||
s3BucketConfiguration;
|
||||
|
||||
return appConfigNormalized;
|
||||
};
|
||||
|
||||
export const AppConfigContainer = {
|
||||
getChannelUrlConfiguration: getChannelUrlConfiguration,
|
||||
setChannelUrlConfiguration: setChannelUrlConfiguration,
|
||||
getChannelUrlConfiguration,
|
||||
setChannelUrlConfiguration,
|
||||
getChannelS3BucketConfiguration,
|
||||
setChannelS3BucketConfiguration,
|
||||
};
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
import { z } from "zod";
|
||||
import { sellerShopConfigSchema } from "./app-config";
|
||||
|
||||
export const appConfigInputSchema = z.object({
|
||||
shopConfigPerChannel: z.record(
|
||||
z.object({
|
||||
urlConfiguration: z.object({
|
||||
/**
|
||||
* min() to allow empty strings
|
||||
*/
|
||||
storefrontUrl: z.string().min(0),
|
||||
productStorefrontUrl: z.string().min(0),
|
||||
}),
|
||||
})
|
||||
),
|
||||
shopConfigPerChannel: z.record(sellerShopConfigSchema),
|
||||
});
|
||||
|
|
|
@ -1,9 +1,31 @@
|
|||
export interface SellerShopConfig {
|
||||
urlConfiguration: {
|
||||
storefrontUrl: string;
|
||||
productStorefrontUrl: string;
|
||||
};
|
||||
}
|
||||
import { z } from "zod";
|
||||
import { UrlConfiguration } from "./url-configuration";
|
||||
|
||||
export const s3BucketConfigurationSchema = z.object({
|
||||
bucketName: z.string(),
|
||||
secretAccessKey: z.string(),
|
||||
accessKeyId: z.string(),
|
||||
region: z.string(),
|
||||
});
|
||||
|
||||
export type S3BucketConfiguration = z.infer<typeof s3BucketConfigurationSchema>;
|
||||
|
||||
export const urlConfigurationSchema = z.object({
|
||||
/**
|
||||
* min() to allow empty strings
|
||||
*/
|
||||
storefrontUrl: z.string().min(0),
|
||||
productStorefrontUrl: z.string().min(0),
|
||||
});
|
||||
|
||||
export type UrlConfiguration = z.infer<typeof urlConfigurationSchema>;
|
||||
|
||||
export const sellerShopConfigSchema = z.object({
|
||||
urlConfiguration: urlConfigurationSchema,
|
||||
s3BucketConfiguration: s3BucketConfigurationSchema.optional(),
|
||||
});
|
||||
|
||||
export type SellerShopConfig = z.infer<typeof sellerShopConfigSchema>;
|
||||
|
||||
export type ShopConfigPerChannelSlug = Record<string, SellerShopConfig>;
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { router } from "../trpc/trpc-server";
|
||||
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
|
||||
import { PrivateMetadataAppConfigurator } from "./app-configurator";
|
||||
import { createSettingsManager } from "./metadata-manager";
|
||||
import { createSettingsManager } from "../../lib/metadata-manager";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import { appConfigInputSchema } from "./app-config-input-schema";
|
||||
import { GetAppConfigurationService } from "./get-app-configuration.service";
|
||||
import { updateCacheForConfigurations } from "../metadata-cache/update-cache-for-configurations";
|
||||
|
||||
export const appConfigurationRouter = router({
|
||||
fetch: protectedClientProcedure.query(async ({ ctx, input }) => {
|
||||
|
@ -30,6 +31,12 @@ export const appConfigurationRouter = router({
|
|||
ctx.saleorApiUrl
|
||||
);
|
||||
|
||||
await updateCacheForConfigurations({
|
||||
client: ctx.apiClient,
|
||||
configurations: input,
|
||||
saleorApiUrl: ctx.saleorApiUrl,
|
||||
});
|
||||
|
||||
await appConfigurator.setConfig(input);
|
||||
|
||||
return null;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { PrivateMetadataAppConfigurator } from "./app-configurator";
|
||||
import { createSettingsManager } from "./metadata-manager";
|
||||
import { createSettingsManager } from "../../lib/metadata-manager";
|
||||
import { ChannelsFetcher } from "../channels/channels-fetcher";
|
||||
import { ShopInfoFetcher } from "../shop-info/shop-info-fetcher";
|
||||
import { FallbackAppConfig } from "./fallback-app-config";
|
||||
|
|
|
@ -10,6 +10,7 @@ import { FeedPreviewCard } from "./feed-preview-card";
|
|||
import { Instructions } from "./instructions";
|
||||
import { SideMenu } from "./side-menu";
|
||||
import { useDashboardNotification } from "@saleor/apps-shared";
|
||||
import { S3ConfigurationForm } from "./s3-configuration-form";
|
||||
|
||||
const useStyles = makeStyles((theme) => {
|
||||
return {
|
||||
|
@ -100,7 +101,7 @@ export const ChannelsConfiguration = () => {
|
|||
<Paper elevation={0}>
|
||||
<UrlConfigurationForm
|
||||
channelID={activeChannel.id}
|
||||
key={activeChannelSlug}
|
||||
key={activeChannelSlug + "url"}
|
||||
channelSlug={activeChannel.slug}
|
||||
onSubmit={async (data) => {
|
||||
const newConfig = AppConfigContainer.setChannelUrlConfiguration(configurationData)(
|
||||
|
@ -114,6 +115,22 @@ export const ChannelsConfiguration = () => {
|
|||
)}
|
||||
channelName={activeChannel?.name ?? activeChannelSlug}
|
||||
/>
|
||||
<S3ConfigurationForm
|
||||
channelID={activeChannel.id}
|
||||
key={activeChannelSlug + "s3"}
|
||||
channelSlug={activeChannel.slug}
|
||||
onSubmit={async (data) => {
|
||||
const newConfig = AppConfigContainer.setChannelS3BucketConfiguration(
|
||||
configurationData
|
||||
)(activeChannel.slug)(data);
|
||||
|
||||
mutate(newConfig);
|
||||
}}
|
||||
initialData={AppConfigContainer.getChannelS3BucketConfiguration(configurationData)(
|
||||
activeChannel.slug
|
||||
)}
|
||||
channelName={activeChannel?.name ?? activeChannelSlug}
|
||||
/>
|
||||
{saveError && <span>{saveError.message}</span>}
|
||||
</Paper>
|
||||
<FeedPreviewCard channelSlug={activeChannel.slug} />
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
import { S3BucketConfiguration, SellerShopConfig } from "../app-config";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { TextField, TextFieldProps, Typography } from "@material-ui/core";
|
||||
import { Button, makeStyles } from "@saleor/macaw-ui";
|
||||
import React from "react";
|
||||
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
field: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
form: {
|
||||
padding: 20,
|
||||
},
|
||||
channelName: {
|
||||
fontFamily: "monospace",
|
||||
cursor: "pointer",
|
||||
},
|
||||
});
|
||||
|
||||
type Props = {
|
||||
channelSlug: string;
|
||||
channelName: string;
|
||||
channelID: string;
|
||||
onSubmit(data: S3BucketConfiguration): Promise<void>;
|
||||
initialData?: S3BucketConfiguration | null;
|
||||
};
|
||||
|
||||
export const S3ConfigurationForm = (props: Props) => {
|
||||
const { register, handleSubmit } = useForm<S3BucketConfiguration>({
|
||||
defaultValues: props.initialData ?? undefined,
|
||||
});
|
||||
const styles = useStyles();
|
||||
const { appBridge } = useAppBridge();
|
||||
|
||||
const CommonFieldProps: TextFieldProps = {
|
||||
className: styles.field,
|
||||
fullWidth: true,
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit((data, event) => {
|
||||
props.onSubmit(data);
|
||||
})}
|
||||
className={styles.form}
|
||||
>
|
||||
<Typography variant="h3" paragraph>
|
||||
S3 storage
|
||||
</Typography>
|
||||
<TextField label="Amazon access key ID" {...CommonFieldProps} {...register("accessKeyId")} />
|
||||
|
||||
<TextField
|
||||
label="Amazon secret access key"
|
||||
{...CommonFieldProps}
|
||||
{...register("secretAccessKey")}
|
||||
/>
|
||||
|
||||
<TextField label="Bucket name" {...CommonFieldProps} {...register("bucketName")} />
|
||||
|
||||
<TextField label="Bucket region" {...CommonFieldProps} {...register("region")} />
|
||||
|
||||
<Button type="submit" fullWidth variant="primary">
|
||||
Save bucket configuration
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
6
apps/products-feed/src/modules/file-storage/s3/const.ts
Normal file
6
apps/products-feed/src/modules/file-storage/s3/const.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
* AWS multipart uploads require a minimum file size of 5 MB.
|
||||
* https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html
|
||||
*/
|
||||
|
||||
export const MULTI_PART_SIZE_THRESHOLD = 5 * 1024 * 1024;
|
|
@ -0,0 +1,16 @@
|
|||
import { S3Client } from "@aws-sdk/client-s3";
|
||||
import { S3BucketConfiguration } from "../../app-configuration/app-config";
|
||||
|
||||
export const createS3ClientFromConfiguration = ({
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
region,
|
||||
}: S3BucketConfiguration) => {
|
||||
return new S3Client({
|
||||
credentials: {
|
||||
accessKeyId: accessKeyId,
|
||||
secretAccessKey: secretAccessKey,
|
||||
},
|
||||
region: region,
|
||||
});
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
import { GetObjectAttributesCommand, S3Client } from "@aws-sdk/client-s3";
|
||||
|
||||
export interface GetFileDetailsArgs {
|
||||
s3Client: S3Client;
|
||||
fileName: string;
|
||||
bucketName: string;
|
||||
}
|
||||
|
||||
export const getFileDetails = async ({ s3Client, bucketName, fileName }: GetFileDetailsArgs) => {
|
||||
return await s3Client.send(
|
||||
new GetObjectAttributesCommand({
|
||||
Bucket: bucketName,
|
||||
Key: fileName,
|
||||
ObjectAttributes: ["ObjectParts"],
|
||||
})
|
||||
);
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
import { S3Client } from "@aws-sdk/client-s3";
|
||||
import { UploadMultiPart } from "./upload-multi-part";
|
||||
import { UploadSinglePart } from "./upload-single-part";
|
||||
import { MULTI_PART_SIZE_THRESHOLD } from "./const";
|
||||
|
||||
export interface UploadFileArgs {
|
||||
s3Client: S3Client;
|
||||
fileName: string;
|
||||
buffer: Buffer;
|
||||
bucketName: string;
|
||||
}
|
||||
|
||||
export const uploadFile = async (args: UploadFileArgs) => {
|
||||
if (args.buffer.length > MULTI_PART_SIZE_THRESHOLD) {
|
||||
return await UploadMultiPart(args);
|
||||
}
|
||||
return await UploadSinglePart(args);
|
||||
};
|
|
@ -0,0 +1,94 @@
|
|||
import {
|
||||
AbortMultipartUploadCommand,
|
||||
CompleteMultipartUploadCommand,
|
||||
CreateMultipartUploadCommand,
|
||||
UploadPartCommand,
|
||||
} from "@aws-sdk/client-s3";
|
||||
import { UploadFileArgs } from "./upload-file";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import { MULTI_PART_SIZE_THRESHOLD } from "./const";
|
||||
|
||||
/*
|
||||
* Code based on S3 docs:
|
||||
* https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html
|
||||
*/
|
||||
|
||||
const logger = createLogger({
|
||||
fn: "UploadMultiPart",
|
||||
});
|
||||
|
||||
export const UploadMultiPart = async ({
|
||||
s3Client,
|
||||
fileName,
|
||||
buffer,
|
||||
bucketName,
|
||||
}: UploadFileArgs) => {
|
||||
let uploadId;
|
||||
|
||||
try {
|
||||
const multipartUpload = await s3Client.send(
|
||||
new CreateMultipartUploadCommand({
|
||||
Bucket: bucketName,
|
||||
Key: fileName,
|
||||
})
|
||||
);
|
||||
|
||||
uploadId = multipartUpload.UploadId;
|
||||
|
||||
const uploadPromises = [];
|
||||
// Multipart uploads require a minimum size of 5 MB per part.
|
||||
const partSize = MULTI_PART_SIZE_THRESHOLD;
|
||||
const numberOfParts = Math.ceil(buffer.length / partSize);
|
||||
|
||||
// Upload each part.
|
||||
for (let i = 0; i < numberOfParts; i++) {
|
||||
const start = i * partSize;
|
||||
const end = start + partSize;
|
||||
|
||||
uploadPromises.push(
|
||||
s3Client
|
||||
.send(
|
||||
new UploadPartCommand({
|
||||
Bucket: bucketName,
|
||||
Key: fileName,
|
||||
UploadId: uploadId,
|
||||
Body: buffer.subarray(start, end),
|
||||
PartNumber: i + 1,
|
||||
})
|
||||
)
|
||||
.then((d) => {
|
||||
logger.debug(`Part ${i + 1}/${numberOfParts} uploaded`);
|
||||
return d;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const uploadResults = await Promise.all(uploadPromises);
|
||||
|
||||
return await s3Client.send(
|
||||
new CompleteMultipartUploadCommand({
|
||||
Bucket: bucketName,
|
||||
Key: fileName,
|
||||
UploadId: uploadId,
|
||||
MultipartUpload: {
|
||||
Parts: uploadResults.map(({ ETag }, i) => ({
|
||||
ETag,
|
||||
PartNumber: i + 1,
|
||||
})),
|
||||
},
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
|
||||
if (uploadId) {
|
||||
const abortCommand = new AbortMultipartUploadCommand({
|
||||
Bucket: bucketName,
|
||||
Key: fileName,
|
||||
UploadId: uploadId,
|
||||
});
|
||||
|
||||
await s3Client.send(abortCommand);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
import { PutObjectCommand } from "@aws-sdk/client-s3";
|
||||
import { UploadFileArgs } from "./upload-file";
|
||||
|
||||
export const UploadSinglePart = async ({
|
||||
s3Client,
|
||||
fileName,
|
||||
buffer,
|
||||
bucketName,
|
||||
}: UploadFileArgs) => {
|
||||
return await s3Client.send(
|
||||
new PutObjectCommand({
|
||||
Bucket: bucketName,
|
||||
Body: buffer,
|
||||
Key: fileName,
|
||||
})
|
||||
);
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
import { S3BucketConfiguration } from "../../app-configuration/app-config";
|
||||
|
||||
interface GetDownloadUrlArgs {
|
||||
s3BucketConfiguration: S3BucketConfiguration;
|
||||
saleorApiUrl: string;
|
||||
channel: string;
|
||||
}
|
||||
|
||||
export const getDownloadUrl = ({
|
||||
s3BucketConfiguration,
|
||||
saleorApiUrl,
|
||||
channel,
|
||||
}: GetDownloadUrlArgs) => {
|
||||
return `https://${s3BucketConfiguration.bucketName}.s3.${
|
||||
s3BucketConfiguration.region
|
||||
}.amazonaws.com/${getFileName({ saleorApiUrl, channel })}`;
|
||||
};
|
||||
|
||||
interface GetFileNameArgs {
|
||||
saleorApiUrl: string;
|
||||
channel: string;
|
||||
}
|
||||
|
||||
export const getFileName = ({ saleorApiUrl, channel }: GetFileNameArgs) => {
|
||||
const apiUrl = new URL(saleorApiUrl);
|
||||
|
||||
return `${apiUrl.hostname}/${channel}/google.xml`;
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
import { SettingsManager } from "@saleor/app-sdk/settings-manager";
|
||||
|
||||
export class CacheConfigurator {
|
||||
private metadataKeyPrefix = "cursor-cache-";
|
||||
|
||||
constructor(private metadataManager: SettingsManager, private saleorApiUrl: string) {}
|
||||
|
||||
get({ channel }: { channel: string }): Promise<string[] | undefined> {
|
||||
return this.metadataManager
|
||||
.get(this.metadataKeyPrefix + channel, this.saleorApiUrl)
|
||||
.then((data) => {
|
||||
if (!data) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid metadata value, can't be parsed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
set({ channel, value }: { channel: string; value: string[] }): Promise<void> {
|
||||
return this.metadataManager.set({
|
||||
key: this.metadataKeyPrefix + channel,
|
||||
value: JSON.stringify(value),
|
||||
domain: this.saleorApiUrl,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import { createLogger } from "@saleor/apps-shared";
|
||||
import { CacheConfigurator } from "./cache-configurator";
|
||||
import { createSettingsManager } from "../../lib/metadata-manager";
|
||||
import { getCursors } from "../../lib/google-feed/fetch-product-data";
|
||||
import { Client } from "urql";
|
||||
import { z } from "zod";
|
||||
import { appConfigInputSchema } from "../app-configuration/app-config-input-schema";
|
||||
|
||||
interface UpdateCacheForConfigurationsArgs {
|
||||
client: Client;
|
||||
saleorApiUrl: string;
|
||||
configurations: z.infer<typeof appConfigInputSchema>;
|
||||
}
|
||||
|
||||
export const updateCacheForConfigurations = async ({
|
||||
client,
|
||||
configurations,
|
||||
saleorApiUrl,
|
||||
}: UpdateCacheForConfigurationsArgs) => {
|
||||
const logger = createLogger({ saleorApiUrl: saleorApiUrl });
|
||||
|
||||
logger.debug("Updating the cursor cache");
|
||||
const cache = new CacheConfigurator(createSettingsManager(client), saleorApiUrl);
|
||||
|
||||
const channelsToUpdate = Object.keys(configurations.shopConfigPerChannel);
|
||||
|
||||
const cacheUpdatePromises = channelsToUpdate.map(async (channel) => {
|
||||
const cursors = await getCursors({ client, channel });
|
||||
|
||||
await cache.set({ channel, value: cursors });
|
||||
});
|
||||
|
||||
await Promise.all(cacheUpdatePromises);
|
||||
logger.debug("Cursor cache updated");
|
||||
};
|
|
@ -7,6 +7,14 @@ import { fetchProductData } from "../../../../../lib/google-feed/fetch-product-d
|
|||
import { getGoogleFeedSettings } from "../../../../../lib/google-feed/get-google-feed-settings";
|
||||
import { generateGoogleXmlFeed } from "../../../../../lib/google-feed/generate-google-xml-feed";
|
||||
import { fetchShopData } from "../../../../../lib/google-feed/fetch-shop-data";
|
||||
import { CacheConfigurator } from "../../../../../modules/metadata-cache/cache-configurator";
|
||||
import { createSettingsManager } from "../../../../../lib/metadata-manager";
|
||||
import { createClient } from "../../../../../lib/create-graphq-client";
|
||||
import { uploadFile } from "../../../../../modules/file-storage/s3/upload-file";
|
||||
import { createS3ClientFromConfiguration } from "../../../../../modules/file-storage/s3/create-s3-client-from-configuration";
|
||||
import { S3BucketConfiguration } from "../../../../../modules/app-configuration/app-config";
|
||||
import { getFileDetails } from "../../../../../modules/file-storage/s3/get-file-details";
|
||||
import { getDownloadUrl, getFileName } from "../../../../../modules/file-storage/s3/urls-and-names";
|
||||
|
||||
// By default we cache the feed for 5 minutes. This can be changed by setting the FEED_CACHE_MAX_AGE
|
||||
const FEED_CACHE_MAX_AGE = process.env.FEED_CACHE_MAX_AGE
|
||||
|
@ -60,12 +68,14 @@ export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
|
||||
let storefrontUrl: string;
|
||||
let productStorefrontUrl: string;
|
||||
let bucketConfiguration: S3BucketConfiguration | undefined;
|
||||
|
||||
try {
|
||||
const settings = await getGoogleFeedSettings({ authData, channel });
|
||||
|
||||
storefrontUrl = settings.storefrontUrl;
|
||||
productStorefrontUrl = settings.productStorefrontUrl;
|
||||
bucketConfiguration = settings.s3BucketConfiguration;
|
||||
} catch (error) {
|
||||
logger.warn("The application has not been configured");
|
||||
return res
|
||||
|
@ -86,11 +96,65 @@ export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
return res.status(500).json({ error: "Could not fetch the shop details" });
|
||||
}
|
||||
|
||||
if (bucketConfiguration) {
|
||||
logger.debug("Bucket configuration found, checking if the feed has been generated recently");
|
||||
const s3Client = createS3ClientFromConfiguration(bucketConfiguration);
|
||||
const fileName = getFileName({
|
||||
saleorApiUrl: authData.saleorApiUrl,
|
||||
channel,
|
||||
});
|
||||
|
||||
const feedLastModificationDate = await getFileDetails({
|
||||
s3Client,
|
||||
bucketName: bucketConfiguration.bucketName,
|
||||
fileName,
|
||||
})
|
||||
.then((data) => data.LastModified)
|
||||
// If the file does not exist, error is thrown and we can ignore it
|
||||
.catch(() => undefined);
|
||||
|
||||
if (feedLastModificationDate) {
|
||||
logger.debug("Feed has been generated previously, checking the last modification date");
|
||||
|
||||
const secondsSinceLastModification = (Date.now() - feedLastModificationDate.getTime()) / 1000;
|
||||
|
||||
if (secondsSinceLastModification < FEED_CACHE_MAX_AGE) {
|
||||
logger.debug("Feed has been generated recently, returning the last version");
|
||||
|
||||
const downloadUrl = getDownloadUrl({
|
||||
s3BucketConfiguration: bucketConfiguration,
|
||||
saleorApiUrl: authData.saleorApiUrl,
|
||||
channel,
|
||||
});
|
||||
|
||||
return res.redirect(downloadUrl);
|
||||
}
|
||||
|
||||
logger.debug("Feed is outdated, generating a new one");
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Generating a new feed");
|
||||
|
||||
const cacheClient = createClient(authData.saleorApiUrl, async () =>
|
||||
Promise.resolve({ token: authData.token })
|
||||
);
|
||||
|
||||
if (!cacheClient) {
|
||||
logger.error("Can't create the gql client");
|
||||
return res.status(500).end();
|
||||
}
|
||||
|
||||
// get cached cursors
|
||||
const cache = new CacheConfigurator(createSettingsManager(cacheClient), authData.saleorApiUrl);
|
||||
|
||||
const cursors = await cache.get({ channel });
|
||||
|
||||
// TODO: instead of separate variants, use group id https://support.google.com/merchants/answer/6324507?hl=en
|
||||
let productVariants: GoogleFeedProductVariantFragment[] = [];
|
||||
|
||||
try {
|
||||
productVariants = await fetchProductData({ client, channel });
|
||||
productVariants = await fetchProductData({ client, channel, cursors });
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return res.status(400).end();
|
||||
|
@ -108,10 +172,43 @@ export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
|
||||
logger.debug("Feed generated. Returning formatted XML");
|
||||
|
||||
if (!bucketConfiguration) {
|
||||
logger.debug("Bucket configuration not found, returning feed directly");
|
||||
|
||||
res.setHeader("Content-Type", "text/xml");
|
||||
res.setHeader("Cache-Control", `s-maxage=${FEED_CACHE_MAX_AGE}`);
|
||||
res.write(xmlContent);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Bucket configuration found, uploading the feed to S3");
|
||||
const s3Client = createS3ClientFromConfiguration(bucketConfiguration);
|
||||
const fileName = getFileName({
|
||||
saleorApiUrl: authData.saleorApiUrl,
|
||||
channel,
|
||||
});
|
||||
|
||||
try {
|
||||
await uploadFile({
|
||||
s3Client,
|
||||
bucketName: bucketConfiguration.bucketName,
|
||||
buffer: Buffer.from(xmlContent),
|
||||
fileName,
|
||||
});
|
||||
|
||||
logger.debug("Feed uploaded to S3, redirecting the download URL");
|
||||
const downloadUrl = getDownloadUrl({
|
||||
s3BucketConfiguration: bucketConfiguration,
|
||||
saleorApiUrl: authData.saleorApiUrl,
|
||||
channel,
|
||||
});
|
||||
|
||||
return res.redirect(downloadUrl);
|
||||
} catch (error) {
|
||||
logger.error("Could not upload the feed to S3");
|
||||
return res.status(500).json({ error: "Could not upload the feed to S3" });
|
||||
}
|
||||
};
|
||||
|
||||
export default handler;
|
||||
|
|
957
pnpm-lock.yaml
957
pnpm-lock.yaml
|
@ -1070,6 +1070,9 @@ importers:
|
|||
|
||||
apps/products-feed:
|
||||
dependencies:
|
||||
'@aws-sdk/client-s3':
|
||||
specifier: ^3.332.0
|
||||
version: 3.332.0
|
||||
'@hookform/resolvers':
|
||||
specifier: ^2.9.10
|
||||
version: 2.9.11(react-hook-form@7.43.1)
|
||||
|
@ -1925,6 +1928,955 @@ packages:
|
|||
- encoding
|
||||
dev: true
|
||||
|
||||
/@aws-crypto/crc32@3.0.0:
|
||||
resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==}
|
||||
dependencies:
|
||||
'@aws-crypto/util': 3.0.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@aws-crypto/crc32c@3.0.0:
|
||||
resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==}
|
||||
dependencies:
|
||||
'@aws-crypto/util': 3.0.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@aws-crypto/ie11-detection@3.0.0:
|
||||
resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==}
|
||||
dependencies:
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@aws-crypto/sha1-browser@3.0.0:
|
||||
resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==}
|
||||
dependencies:
|
||||
'@aws-crypto/ie11-detection': 3.0.0
|
||||
'@aws-crypto/supports-web-crypto': 3.0.0
|
||||
'@aws-crypto/util': 3.0.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-locate-window': 3.310.0
|
||||
'@aws-sdk/util-utf8-browser': 3.259.0
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@aws-crypto/sha256-browser@3.0.0:
|
||||
resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==}
|
||||
dependencies:
|
||||
'@aws-crypto/ie11-detection': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-crypto/supports-web-crypto': 3.0.0
|
||||
'@aws-crypto/util': 3.0.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-locate-window': 3.310.0
|
||||
'@aws-sdk/util-utf8-browser': 3.259.0
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@aws-crypto/sha256-js@3.0.0:
|
||||
resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==}
|
||||
dependencies:
|
||||
'@aws-crypto/util': 3.0.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@aws-crypto/supports-web-crypto@3.0.0:
|
||||
resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==}
|
||||
dependencies:
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@aws-crypto/util@3.0.0:
|
||||
resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-utf8-browser': 3.259.0
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/abort-controller@3.329.0:
|
||||
resolution: {integrity: sha512-hzrjPNQcJoSPe0oS20V5i98oiEZSM3mKNiR6P3xHTHTPI/F23lyjGZ+/CSkCmJbSWfGZ5sHZZcU6AWuS7xBdTw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/chunked-blob-reader@3.310.0:
|
||||
resolution: {integrity: sha512-CrJS3exo4mWaLnWxfCH+w88Ou0IcAZSIkk4QbmxiHl/5Dq705OLoxf4385MVyExpqpeVJYOYQ2WaD8i/pQZ2fg==}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/client-s3@3.332.0:
|
||||
resolution: {integrity: sha512-4AkbBPGjFkIvN15l9uDHcry3kwMknpl0b7mqFaNQqQJR2OyFJnr7US/KyeTjwijJAuU+f7lKz8QMTtBcghJm3w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-crypto/sha1-browser': 3.0.0
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sts': 3.332.0
|
||||
'@aws-sdk/config-resolver': 3.329.0
|
||||
'@aws-sdk/credential-provider-node': 3.332.0
|
||||
'@aws-sdk/eventstream-serde-browser': 3.329.0
|
||||
'@aws-sdk/eventstream-serde-config-resolver': 3.329.0
|
||||
'@aws-sdk/eventstream-serde-node': 3.329.0
|
||||
'@aws-sdk/fetch-http-handler': 3.329.0
|
||||
'@aws-sdk/hash-blob-browser': 3.329.0
|
||||
'@aws-sdk/hash-node': 3.329.0
|
||||
'@aws-sdk/hash-stream-node': 3.329.0
|
||||
'@aws-sdk/invalid-dependency': 3.329.0
|
||||
'@aws-sdk/md5-js': 3.329.0
|
||||
'@aws-sdk/middleware-bucket-endpoint': 3.329.0
|
||||
'@aws-sdk/middleware-content-length': 3.329.0
|
||||
'@aws-sdk/middleware-endpoint': 3.329.0
|
||||
'@aws-sdk/middleware-expect-continue': 3.329.0
|
||||
'@aws-sdk/middleware-flexible-checksums': 3.331.0
|
||||
'@aws-sdk/middleware-host-header': 3.329.0
|
||||
'@aws-sdk/middleware-location-constraint': 3.329.0
|
||||
'@aws-sdk/middleware-logger': 3.329.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.329.0
|
||||
'@aws-sdk/middleware-retry': 3.329.0
|
||||
'@aws-sdk/middleware-sdk-s3': 3.329.0
|
||||
'@aws-sdk/middleware-serde': 3.329.0
|
||||
'@aws-sdk/middleware-signing': 3.329.0
|
||||
'@aws-sdk/middleware-ssec': 3.329.0
|
||||
'@aws-sdk/middleware-stack': 3.329.0
|
||||
'@aws-sdk/middleware-user-agent': 3.332.0
|
||||
'@aws-sdk/node-config-provider': 3.329.0
|
||||
'@aws-sdk/node-http-handler': 3.329.0
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/signature-v4-multi-region': 3.329.0
|
||||
'@aws-sdk/smithy-client': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/url-parser': 3.329.0
|
||||
'@aws-sdk/util-base64': 3.310.0
|
||||
'@aws-sdk/util-body-length-browser': 3.310.0
|
||||
'@aws-sdk/util-body-length-node': 3.310.0
|
||||
'@aws-sdk/util-defaults-mode-browser': 3.329.0
|
||||
'@aws-sdk/util-defaults-mode-node': 3.329.0
|
||||
'@aws-sdk/util-endpoints': 3.332.0
|
||||
'@aws-sdk/util-retry': 3.329.0
|
||||
'@aws-sdk/util-stream-browser': 3.329.0
|
||||
'@aws-sdk/util-stream-node': 3.331.0
|
||||
'@aws-sdk/util-user-agent-browser': 3.329.0
|
||||
'@aws-sdk/util-user-agent-node': 3.329.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
'@aws-sdk/util-waiter': 3.329.0
|
||||
'@aws-sdk/xml-builder': 3.310.0
|
||||
fast-xml-parser: 4.1.2
|
||||
tslib: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/signature-v4-crt'
|
||||
- aws-crt
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/client-sso-oidc@3.332.0:
|
||||
resolution: {integrity: sha512-tz8k8Yqm4TScIfit0Tum2zWAq1md+gZKr747CSixd4Zwcp7Vwh75cRoL7Rz1ZHSEn1Yo983MWREevVez3SubLw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/config-resolver': 3.329.0
|
||||
'@aws-sdk/fetch-http-handler': 3.329.0
|
||||
'@aws-sdk/hash-node': 3.329.0
|
||||
'@aws-sdk/invalid-dependency': 3.329.0
|
||||
'@aws-sdk/middleware-content-length': 3.329.0
|
||||
'@aws-sdk/middleware-endpoint': 3.329.0
|
||||
'@aws-sdk/middleware-host-header': 3.329.0
|
||||
'@aws-sdk/middleware-logger': 3.329.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.329.0
|
||||
'@aws-sdk/middleware-retry': 3.329.0
|
||||
'@aws-sdk/middleware-serde': 3.329.0
|
||||
'@aws-sdk/middleware-stack': 3.329.0
|
||||
'@aws-sdk/middleware-user-agent': 3.332.0
|
||||
'@aws-sdk/node-config-provider': 3.329.0
|
||||
'@aws-sdk/node-http-handler': 3.329.0
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/smithy-client': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/url-parser': 3.329.0
|
||||
'@aws-sdk/util-base64': 3.310.0
|
||||
'@aws-sdk/util-body-length-browser': 3.310.0
|
||||
'@aws-sdk/util-body-length-node': 3.310.0
|
||||
'@aws-sdk/util-defaults-mode-browser': 3.329.0
|
||||
'@aws-sdk/util-defaults-mode-node': 3.329.0
|
||||
'@aws-sdk/util-endpoints': 3.332.0
|
||||
'@aws-sdk/util-retry': 3.329.0
|
||||
'@aws-sdk/util-user-agent-browser': 3.329.0
|
||||
'@aws-sdk/util-user-agent-node': 3.329.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
tslib: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/client-sso@3.332.0:
|
||||
resolution: {integrity: sha512-4q1Nko8M6YVANdEiLYvdv1qb00j4xN4ppE/6d4xpGp7DxHYlm0GA762h0/TR2dun+2I+SMnwj4Fv6BxOmzBaEw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/config-resolver': 3.329.0
|
||||
'@aws-sdk/fetch-http-handler': 3.329.0
|
||||
'@aws-sdk/hash-node': 3.329.0
|
||||
'@aws-sdk/invalid-dependency': 3.329.0
|
||||
'@aws-sdk/middleware-content-length': 3.329.0
|
||||
'@aws-sdk/middleware-endpoint': 3.329.0
|
||||
'@aws-sdk/middleware-host-header': 3.329.0
|
||||
'@aws-sdk/middleware-logger': 3.329.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.329.0
|
||||
'@aws-sdk/middleware-retry': 3.329.0
|
||||
'@aws-sdk/middleware-serde': 3.329.0
|
||||
'@aws-sdk/middleware-stack': 3.329.0
|
||||
'@aws-sdk/middleware-user-agent': 3.332.0
|
||||
'@aws-sdk/node-config-provider': 3.329.0
|
||||
'@aws-sdk/node-http-handler': 3.329.0
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/smithy-client': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/url-parser': 3.329.0
|
||||
'@aws-sdk/util-base64': 3.310.0
|
||||
'@aws-sdk/util-body-length-browser': 3.310.0
|
||||
'@aws-sdk/util-body-length-node': 3.310.0
|
||||
'@aws-sdk/util-defaults-mode-browser': 3.329.0
|
||||
'@aws-sdk/util-defaults-mode-node': 3.329.0
|
||||
'@aws-sdk/util-endpoints': 3.332.0
|
||||
'@aws-sdk/util-retry': 3.329.0
|
||||
'@aws-sdk/util-user-agent-browser': 3.329.0
|
||||
'@aws-sdk/util-user-agent-node': 3.329.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
tslib: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/client-sts@3.332.0:
|
||||
resolution: {integrity: sha512-uVobnXIzMcEhwBDyk6iOt36N/TRNI8hwq7MQugjYGj7Inma9g4vnR09hXJ24HxyKCoVUoIgMbEguQ43+/+uvDQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/config-resolver': 3.329.0
|
||||
'@aws-sdk/credential-provider-node': 3.332.0
|
||||
'@aws-sdk/fetch-http-handler': 3.329.0
|
||||
'@aws-sdk/hash-node': 3.329.0
|
||||
'@aws-sdk/invalid-dependency': 3.329.0
|
||||
'@aws-sdk/middleware-content-length': 3.329.0
|
||||
'@aws-sdk/middleware-endpoint': 3.329.0
|
||||
'@aws-sdk/middleware-host-header': 3.329.0
|
||||
'@aws-sdk/middleware-logger': 3.329.0
|
||||
'@aws-sdk/middleware-recursion-detection': 3.329.0
|
||||
'@aws-sdk/middleware-retry': 3.329.0
|
||||
'@aws-sdk/middleware-sdk-sts': 3.329.0
|
||||
'@aws-sdk/middleware-serde': 3.329.0
|
||||
'@aws-sdk/middleware-signing': 3.329.0
|
||||
'@aws-sdk/middleware-stack': 3.329.0
|
||||
'@aws-sdk/middleware-user-agent': 3.332.0
|
||||
'@aws-sdk/node-config-provider': 3.329.0
|
||||
'@aws-sdk/node-http-handler': 3.329.0
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/smithy-client': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/url-parser': 3.329.0
|
||||
'@aws-sdk/util-base64': 3.310.0
|
||||
'@aws-sdk/util-body-length-browser': 3.310.0
|
||||
'@aws-sdk/util-body-length-node': 3.310.0
|
||||
'@aws-sdk/util-defaults-mode-browser': 3.329.0
|
||||
'@aws-sdk/util-defaults-mode-node': 3.329.0
|
||||
'@aws-sdk/util-endpoints': 3.332.0
|
||||
'@aws-sdk/util-retry': 3.329.0
|
||||
'@aws-sdk/util-user-agent-browser': 3.329.0
|
||||
'@aws-sdk/util-user-agent-node': 3.329.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
fast-xml-parser: 4.1.2
|
||||
tslib: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/config-resolver@3.329.0:
|
||||
resolution: {integrity: sha512-Oj6eiT3q+Jn685yvUrfRi8PhB3fb81hasJqdrsEivA8IP8qAgnVUTJzXsh8O2UX8UM2MF6A1gTgToSgneJuw2Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-config-provider': 3.310.0
|
||||
'@aws-sdk/util-middleware': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/credential-provider-env@3.329.0:
|
||||
resolution: {integrity: sha512-B4orC9hMt9hG82vAR0TAnQqjk6cFDbO2S14RdzUj2n2NPlGWW4Blkv3NTo86K0lq011VRhtqaLcuTwn5EJD5Sg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/credential-provider-imds@3.329.0:
|
||||
resolution: {integrity: sha512-ggPlnd7QROPTid0CwT01TYYGvstRRTpzTGsQ/B31wkh30IrRXE81W3S4xrOYuqQD3u0RnflSxnvhs+EayJEYjg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/node-config-provider': 3.329.0
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/url-parser': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/credential-provider-ini@3.332.0:
|
||||
resolution: {integrity: sha512-DTW6d6rcqizPVyvcIrwvxecQ7e5GONtVc5Wyf0RTfqf41sDOVZYmn6G+zEFSpBLW0975uZbJS0lyLWtJe2VujQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/credential-provider-env': 3.329.0
|
||||
'@aws-sdk/credential-provider-imds': 3.329.0
|
||||
'@aws-sdk/credential-provider-process': 3.329.0
|
||||
'@aws-sdk/credential-provider-sso': 3.332.0
|
||||
'@aws-sdk/credential-provider-web-identity': 3.329.0
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/shared-ini-file-loader': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/credential-provider-node@3.332.0:
|
||||
resolution: {integrity: sha512-KkBayS9k4WyJTvC86ngeRM+RmWxNCS1BHvudkR6PLXfnsNPDzxySDVY0UgxVhbNYDYsO561fXZt9ccpKyVWjgg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/credential-provider-env': 3.329.0
|
||||
'@aws-sdk/credential-provider-imds': 3.329.0
|
||||
'@aws-sdk/credential-provider-ini': 3.332.0
|
||||
'@aws-sdk/credential-provider-process': 3.329.0
|
||||
'@aws-sdk/credential-provider-sso': 3.332.0
|
||||
'@aws-sdk/credential-provider-web-identity': 3.329.0
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/shared-ini-file-loader': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/credential-provider-process@3.329.0:
|
||||
resolution: {integrity: sha512-5oO220qoFc2pMdZDQa6XN/mVhp669I3+LqMbbscGtX/UgLJPSOb7YzPld9Wjv12L5rf+sD3G1PF3LZXO0vKLFA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/shared-ini-file-loader': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/credential-provider-sso@3.332.0:
|
||||
resolution: {integrity: sha512-SaKXl48af3n6LRitcaEqbeg1YDXwQ0A5QziC1xQyYPraEIj3IZ/GyTjx04Lo2jxNYHuEOE8u4aTw1+IK1GDKbg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/client-sso': 3.332.0
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/shared-ini-file-loader': 3.329.0
|
||||
'@aws-sdk/token-providers': 3.332.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/credential-provider-web-identity@3.329.0:
|
||||
resolution: {integrity: sha512-lcEibZD7AlutCacpQ6DyNUqElZJDq+ylaIo5a8MH9jGh7Pg2WpDg0Sy+B6FbGCkVn4eIjdHxeX54JM245nhESg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/eventstream-codec@3.329.0:
|
||||
resolution: {integrity: sha512-1r+6MNfye0za35FNLxMR5V9zpKY1lyzwySyu7o7aj8lnStBaCcjOEe7iHboP/z3DH73KJbxR++O2N+UC/XHFrg==}
|
||||
dependencies:
|
||||
'@aws-crypto/crc32': 3.0.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-hex-encoding': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/eventstream-serde-browser@3.329.0:
|
||||
resolution: {integrity: sha512-oWFSn4o6sxlbFF0AIuDJYf7N0fkiOyWvYgRW3VTX9FSbd66f/KnDspdxIasaDPDUzJl5YRMwUvQbPWw8y9ZQfQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/eventstream-serde-universal': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/eventstream-serde-config-resolver@3.329.0:
|
||||
resolution: {integrity: sha512-iQguqvTtxWXAIniaWmmAO0Qy8080fqnS309p9jbYzz7KaT90sNSCX+CxGFHPy5F0QY36uklDdHn1d1fwWTZciA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/eventstream-serde-node@3.329.0:
|
||||
resolution: {integrity: sha512-+DFia0wdZiHpdOKjBcl1baZjtzPKf4U4MvOpsUpC6CeW1kSy0hoikKzJstNvRb1qxrTSamElT4gKkMHxxVhPBQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/eventstream-serde-universal': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/eventstream-serde-universal@3.329.0:
|
||||
resolution: {integrity: sha512-n9UzW6HKAhVD5wuz3FMC1ew3VI/vUvRSPXGUpKReMiR2z+YyjmuW8UM4nn7q6i7A/I4QHBt1TC/ax/J2yupgPg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/eventstream-codec': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/fetch-http-handler@3.329.0:
|
||||
resolution: {integrity: sha512-9jfIeJhYCcTX4ScXOueRTB3S/tVce0bRsKxKDP0PnTxnGYOwKXoM9lAPmiYItzYmQ/+QzjTI8xfkA9Usz2SK/Q==}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/querystring-builder': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-base64': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/hash-blob-browser@3.329.0:
|
||||
resolution: {integrity: sha512-F5HwXYYSpJtUJqmCRKbz/xwDdOyxKpu69TlfsliECLvAQiQGMh2GO1wGm7grolgTROVVqLYRKk2TSJl/WBg1pw==}
|
||||
dependencies:
|
||||
'@aws-sdk/chunked-blob-reader': 3.310.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/hash-node@3.329.0:
|
||||
resolution: {integrity: sha512-6RmnWXNWpi7yAs0oRDQlkMn2wfXOStr/8kTCgiAiqrk1KopGSBkC2veKiKRSfv02FTd1yV/ISqYNIRqW1VLyxg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-buffer-from': 3.310.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/hash-stream-node@3.329.0:
|
||||
resolution: {integrity: sha512-blSZcb/hJyw3c1bH2Hc1aRoRgruNhRK/qc2svq5kXQFW+qBI5O4fwJayKSdo62/Wh2ejR/N06teYQ9haQLVJEA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/invalid-dependency@3.329.0:
|
||||
resolution: {integrity: sha512-UXynGusDxN/HxLma5ByJ7u+XnuMd47NbHOjJgYsaAjb1CVZT7hEPXOB+mcZ+Ku7To5SCOKu2QbRn7m4bGespBg==}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/is-array-buffer@3.310.0:
|
||||
resolution: {integrity: sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/md5-js@3.329.0:
|
||||
resolution: {integrity: sha512-newSeHd+CO2hNmXhQOrUk5Y1hH7BsJ5J4IldcqHKY93UwWqvQNiepRowSa2bV5EuS1qx3kfXhD66PFNRprrIlQ==}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-bucket-endpoint@3.329.0:
|
||||
resolution: {integrity: sha512-h3/JdK+FmJ/nxLcd8QciJYLy0B4QRsYqqxSffXJ7DYlDjEhUgvVpfGdVgAYHrTtOP8rHSG/K7l7iY7QqTaZpuw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-arn-parser': 3.310.0
|
||||
'@aws-sdk/util-config-provider': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-content-length@3.329.0:
|
||||
resolution: {integrity: sha512-7kCd+CvY/4KbyXB0uyL7jCwPjMi2yERMALFdEH9dsUciwmxIQT6eSc4aF6wImC4UrbafaqmXvvHErABKMVBTKA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-endpoint@3.329.0:
|
||||
resolution: {integrity: sha512-hdJRoNdCM0BT4W+rrtee+kfFRgGPGXQDgtbIQlf/FuuuYz2sdef7/SYWr0mxuncnVBW5WkYSPP8h6q07whSKbg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/middleware-serde': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/url-parser': 3.329.0
|
||||
'@aws-sdk/util-middleware': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-expect-continue@3.329.0:
|
||||
resolution: {integrity: sha512-E/Jp2KijdR/BwF4s899xcSN4/bbHqYznwmBRL5PiHI+HImA6aZ11qTP8kPt5U5p0l2j5iTmW3FpMnByQKJP5Dw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-flexible-checksums@3.331.0:
|
||||
resolution: {integrity: sha512-rdRa4yvyqSQ/HDCh4p1Glv8Y/uRNuIwmOG4nDuL6/GYK1BQdpUpbgrhsszPormku10SnbAdsaWGmVhy3qlUSCQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-crypto/crc32': 3.0.0
|
||||
'@aws-crypto/crc32c': 3.0.0
|
||||
'@aws-sdk/is-array-buffer': 3.310.0
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-host-header@3.329.0:
|
||||
resolution: {integrity: sha512-JrHeUdTIpTCfXDo9JpbAbZTS1x4mt63CCytJRq0mpWp+FlP9hjckBcNxWdR/wSKEzP9pDRnTri638BOwWH7O8w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-location-constraint@3.329.0:
|
||||
resolution: {integrity: sha512-iUTkyXyhchqoEPkdMZSkHhRQmXe0El1+r9oOw8y9JN6IY0T1bnaqUlerGXzb/tQUeENk9OXYuvDHExegHjEWug==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-logger@3.329.0:
|
||||
resolution: {integrity: sha512-lKeeTXsYC1NiwmxrXsZepcwNXPoQxTNNbeD1qaCELPGK2cJlrGoeAP2YRWzpwO2kNZWrDLaGAPT/EUEhqw+d1w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-recursion-detection@3.329.0:
|
||||
resolution: {integrity: sha512-0/TYOJwrj1Z8s+Y7thibD23hggBq/K/01NwPk32CwWG/G+1vWozs5DefknEl++w0vuV+39pkY4KHI8m/+wOCpg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-retry@3.329.0:
|
||||
resolution: {integrity: sha512-cB3D7GlhHUcHGOlygOYxD9cPhwsTYEAMcohK38An8+RHNp6VQEWezzLFCmHVKUSeCQ+wkjZfPA40jOG0rbjSgQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/service-error-classification': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-middleware': 3.329.0
|
||||
'@aws-sdk/util-retry': 3.329.0
|
||||
tslib: 2.5.0
|
||||
uuid: 8.3.2
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-sdk-s3@3.329.0:
|
||||
resolution: {integrity: sha512-Uo8dLXLDpOb3BnLVl0mkTPiVXlNzNGOXOVtpihvYhF2Z+hGFJW1Ro3aUDbVEsFHu753r2Lss4dLiq1fzREeBKA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-arn-parser': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-sdk-sts@3.329.0:
|
||||
resolution: {integrity: sha512-bqtZuhkH8pANb2Gb4FEM1p27o+BoDBmVhEWm8sWH+APsyOor3jc6eUG2GxkfoO6D5tGNIuyCC/GuvW9XDIe4Kg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/middleware-signing': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-serde@3.329.0:
|
||||
resolution: {integrity: sha512-tvM9NdPuRPCozPjTGNOeYZeLlyx3BcEyajrkRorCRf1YzG/mXdB6I1stote7i4q1doFtYTz0sYL8bqW3LUPn9A==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-signing@3.329.0:
|
||||
resolution: {integrity: sha512-bL1nI+EUcF5B1ipwDXxiKL+Uw02Mbt/TNX54PbzunBGZIyO6DZG/H+M3U296bYbvPlwlZhp26O830g6K7VEWsA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/signature-v4': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-middleware': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-ssec@3.329.0:
|
||||
resolution: {integrity: sha512-XtDA/P2Sf79scu4a7tG77QC3VLtAGq/pit73x+qwctnI4gBgZlQ+FpE15d89ulntd7rIaD4v6tVU0bAg/L3PIQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-stack@3.329.0:
|
||||
resolution: {integrity: sha512-2huFLhJ45td2nuiIOjpc9JKJbFNn5CYmw9U8YDITTcydpteRN62CzCpeqroDvF89VOLWxh0ZFtuLCGUr7liSWQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-user-agent@3.332.0:
|
||||
resolution: {integrity: sha512-rSL1xP4QmcMOsunN1p5ZDR9GT3vvoSCnYa4iPvMSjP8Jx7l4ff/aVctwfZkMs/up12+68Jqwj4TvtaCvCFXdUA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-endpoints': 3.332.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/node-config-provider@3.329.0:
|
||||
resolution: {integrity: sha512-hg9rGNlkzh8aeR/sQbijrkFx2BIO53j4Z6qDxPNWwSGpl05jri1VHxHx2HZMwgbY6Zy/DSguETN/BL8vdFqyLg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/shared-ini-file-loader': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/node-http-handler@3.329.0:
|
||||
resolution: {integrity: sha512-OrjaHjU2ZTPfoHa5DruRvTIbeHH/cc0wvh4ml+FwDpWaPaBpOhLiluhZ3anqX1l5QjrXNiQnL8FxSM5OV/zVCA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/abort-controller': 3.329.0
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/querystring-builder': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/property-provider@3.329.0:
|
||||
resolution: {integrity: sha512-1cHLTV6yyMGaMSWWDW/p4vTkJ1cc5BOEO+A0eHuAcoSOk+LDe9IKhUG3/ZOvvYKQYcqIj5jjGSni/noXNCl/qw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/protocol-http@3.329.0:
|
||||
resolution: {integrity: sha512-0rLEHY6QTHTUUcVxzGbPUSmCKlXWplxT/fcYRh0bcc5MBK4naKfcQft1O6Ajp8uqs/9YPZ7XCVCn90pDeJfeaw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/querystring-builder@3.329.0:
|
||||
resolution: {integrity: sha512-UWgMKkS5trliaDJG4nPv3onu8Y0aBuwRo7RdIgggguOiU8pU6pq1I113nH2FBNWy+Me1bwf+bcviJh0pCo6bEg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-uri-escape': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/querystring-parser@3.329.0:
|
||||
resolution: {integrity: sha512-9mkK+FB7snJ2G7H3CqtprDwYIRhzm6jEezffCwUWrC+lbqHBbErbhE9IeU/MKxILmf0RbC2riXEY1MHGspjRrQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/service-error-classification@3.329.0:
|
||||
resolution: {integrity: sha512-TSNr0flOcCLe71aPp7MjblKNGsmxpTU4xR5772MDX9Cz9GUTNZCPFtvrcqd+wzEPP/AC7XwNXe8KjoXooZImUQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/shared-ini-file-loader@3.329.0:
|
||||
resolution: {integrity: sha512-e0hyd75fbjMd4aCoRwpP2/HR+0oScwogErVArIkq3F42c/hyNCQP3sph4JImuXIjuo6HNnpKpf20CEPPhNna8A==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/signature-v4-multi-region@3.329.0:
|
||||
resolution: {integrity: sha512-SiK1ez8Ns61ulDm0MJsTOSGNJNOMNoPgfA9i+Uu/VMCBkotZASuxrcSWW8seQnLEynWLerjUF9CYpCQuCqKn9w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@aws-sdk/signature-v4-crt': ^3.118.0
|
||||
peerDependenciesMeta:
|
||||
'@aws-sdk/signature-v4-crt':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@aws-sdk/protocol-http': 3.329.0
|
||||
'@aws-sdk/signature-v4': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/signature-v4@3.329.0:
|
||||
resolution: {integrity: sha512-9EnLoyOD5nFtCRAp+QRllDgQASCfY7jLHVhwht7jzwE80wE65Z9Ym5Z/mwTd4IyTz/xXfCvcE2VwClsBt0Ybdw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/is-array-buffer': 3.310.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-hex-encoding': 3.310.0
|
||||
'@aws-sdk/util-middleware': 3.329.0
|
||||
'@aws-sdk/util-uri-escape': 3.310.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/smithy-client@3.329.0:
|
||||
resolution: {integrity: sha512-7E0fGpBKxwFqHHAOqNbgNsHSEmCZLuvmU9yvG9DXKVzrS4P48O/PfOro123WpcFZs3STyOVgH8wjUPftHAVKmg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/middleware-stack': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/token-providers@3.332.0:
|
||||
resolution: {integrity: sha512-fccbg6OSl0l658pxl2p1MoU9gEePo5B361+JNaN0zfRMu7c5HBXCpdl4djlFxAHjltrX9f1+BKqfGHYgI3h8SQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/client-sso-oidc': 3.332.0
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/shared-ini-file-loader': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/types@3.329.0:
|
||||
resolution: {integrity: sha512-wFBW4yciDfzQBSFmWNaEvHShnSGLMxSu9Lls6EUf6xDMavxSB36bsrVRX6CyAo/W0NeIIyEOW1LclGPgJV1okg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/url-parser@3.329.0:
|
||||
resolution: {integrity: sha512-/VcfL7vNJKJGSjYYHVQF3bYCDFs4fSzB7j5qeVDwRdWr870gE7O1Dar+sLWBRKFF3AX+4VzplqzUfpu9t44JVA==}
|
||||
dependencies:
|
||||
'@aws-sdk/querystring-parser': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-arn-parser@3.310.0:
|
||||
resolution: {integrity: sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-base64@3.310.0:
|
||||
resolution: {integrity: sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/util-buffer-from': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-body-length-browser@3.310.0:
|
||||
resolution: {integrity: sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-body-length-node@3.310.0:
|
||||
resolution: {integrity: sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-buffer-from@3.310.0:
|
||||
resolution: {integrity: sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/is-array-buffer': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-config-provider@3.310.0:
|
||||
resolution: {integrity: sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-defaults-mode-browser@3.329.0:
|
||||
resolution: {integrity: sha512-2iSiy/pzX3OXMhtSxtAzOiEFr3viQEFnYOTeZuiheuyS+cea2L79F6SlZ1110b/nOIU/UOrxxtz83HVad8YFMQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
bowser: 2.11.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-defaults-mode-node@3.329.0:
|
||||
resolution: {integrity: sha512-7A6C7YKjkZtmKtH29isYEtOCbhd7IcXPP8lftN8WAWlLOiZE4gV7PHveagUj7QserJzgRKGwwTQbBj53n18HYg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/config-resolver': 3.329.0
|
||||
'@aws-sdk/credential-provider-imds': 3.329.0
|
||||
'@aws-sdk/node-config-provider': 3.329.0
|
||||
'@aws-sdk/property-provider': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-endpoints@3.332.0:
|
||||
resolution: {integrity: sha512-nQx7AiOroMU2hj6h+umWOSZ+WECwxupaxFUK/PPKGW6NY/VdQE6LluYnXOtF5awlr8w1nPksT0Lq05PZutMDLA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-hex-encoding@3.310.0:
|
||||
resolution: {integrity: sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-locate-window@3.310.0:
|
||||
resolution: {integrity: sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-middleware@3.329.0:
|
||||
resolution: {integrity: sha512-RhBOBaxzkTUghi4MSqr8S5qeeBCjgJ0XPJ6jIYkVkj1saCmqkuZCgl3zFaYdyhdxxPV6nflkFer+1HUoqT+Fqw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-retry@3.329.0:
|
||||
resolution: {integrity: sha512-+3VQ9HZLinysnmryUs9Xjt1YVh4TYYHLt30ilu4iUnIHFQoamdzIbRCWseSVFPCxGroen9M9qmAleAsytHEKuA==}
|
||||
engines: {node: '>= 14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/service-error-classification': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-stream-browser@3.329.0:
|
||||
resolution: {integrity: sha512-UF1fJNfgrdJLMxn8ZlfPkYdv7hoLvVgSk3GHgxYA4OQs5zKCzeZgVrbxtE147LxWwJbxi3Qf04vnaEHwzVESpg==}
|
||||
dependencies:
|
||||
'@aws-sdk/fetch-http-handler': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-base64': 3.310.0
|
||||
'@aws-sdk/util-hex-encoding': 3.310.0
|
||||
'@aws-sdk/util-utf8': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-stream-node@3.331.0:
|
||||
resolution: {integrity: sha512-5YUatdh4vgkv7VFY+lSkF+b+6EFkiHvy+dlucfGoJEOcEzuA/NBZYebWbcJ5TiR6z3cQdA23OTyZz3ZofZY1hw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/node-http-handler': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
'@aws-sdk/util-buffer-from': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-uri-escape@3.310.0:
|
||||
resolution: {integrity: sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-user-agent-browser@3.329.0:
|
||||
resolution: {integrity: sha512-8hLSmMCl8aw2++0Zuba8ELq8FkK6/VNyx470St201IpMn2GMbQMDl/rLolRKiTgji6wc+T3pOTidkJkz8/cIXA==}
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.329.0
|
||||
bowser: 2.11.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-user-agent-node@3.329.0:
|
||||
resolution: {integrity: sha512-C50Zaeodc0+psEP+L4WpElrH8epuLWJPVN4hDOTORcM0cSoU2o025Ost9mbcU7UdoHNxF9vitLnzORGN9SHolg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
aws-crt: '>=1.0.0'
|
||||
peerDependenciesMeta:
|
||||
aws-crt:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@aws-sdk/node-config-provider': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-utf8-browser@3.259.0:
|
||||
resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-utf8@3.310.0:
|
||||
resolution: {integrity: sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/util-buffer-from': 3.310.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-waiter@3.329.0:
|
||||
resolution: {integrity: sha512-MIGs7snNL0ZV55zo1BDVPlrmbinUGV3260hp6HrW4zUbpYVoeIOGeewtrwAsF6FJ+vpZCxljPBB0X2jYR7Q7ZQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
'@aws-sdk/abort-controller': 3.329.0
|
||||
'@aws-sdk/types': 3.329.0
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/xml-builder@3.310.0:
|
||||
resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@babel/code-frame@7.21.4:
|
||||
resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
@ -5545,6 +6497,7 @@ packages:
|
|||
uuid: 8.3.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@saleor/app-sdk@0.38.0(next@13.3.0)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-JS/E3YODFHc+1DI+PczbV8jB09nLwzdQcwNs681RlwvR3JUC892hdBYYRdBKG5lauAcr4IxKw1IbrsxJKngtWA==}
|
||||
|
@ -8267,6 +9220,10 @@ packages:
|
|||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||
dev: false
|
||||
|
||||
/bowser@2.11.0:
|
||||
resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
|
||||
dev: false
|
||||
|
||||
/brace-expansion@1.1.11:
|
||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||
dependencies:
|
||||
|
|
Loading…
Reference in a new issue