Compare commits
4 commits
dependabot
...
main
Author | SHA1 | Date | |
---|---|---|---|
4b12982597 | |||
292a5bdb0c | |||
![]() |
653b98df86 | ||
![]() |
ae6dbb125b |
33 changed files with 173 additions and 470 deletions
8
.changeset/pretty-pink-panda.md
Normal file
8
.changeset/pretty-pink-panda.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
#changelog
|
||||
---
|
||||
"apps": minor
|
||||
---
|
||||
### Added
|
||||
|
||||
- `apps/emails-and-messages/.env.template`: Described the new environment variable and how it works
|
||||
- `apps/emails-and-messages/src/saleor-app.ts`: Added case "redis" for switch(AplType), which takes advantage of the [RedisAPL PR](https://github.com/saleor/app-sdk/pull/287) I submitted
|
|
@ -7,6 +7,12 @@ APL=
|
|||
REST_APL_ENDPOINT=
|
||||
REST_APL_TOKEN=
|
||||
|
||||
# To use Redis as an APL store, set APP_API_BASE_URL and REDIS_URL.
|
||||
# URL is in format redis[s]://[[username][:password]@][host][:port][/db-number],
|
||||
# so for example redis://alice:foobared@awesome.redis.server:6380
|
||||
# For saleor-platform, thats: `redis://redis:6379/1`
|
||||
REDIS_URL=
|
||||
|
||||
APP_LOG_LEVEL=info
|
||||
|
||||
# Local development variables. When developped locally with Saleor inside docker, these can be set to:
|
||||
|
@ -15,4 +21,5 @@ APP_LOG_LEVEL=info
|
|||
# If developped with tunnels, set this empty, it will fallback to default Next's localhost:3000
|
||||
# https://docs.saleor.io/docs/3.x/developer/extending/apps/local-app-development
|
||||
APP_IFRAME_BASE_URL=
|
||||
APP_API_BASE_URL=
|
||||
APP_API_BASE_URL=
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { APL, FileAPL, SaleorCloudAPL, UpstashAPL } from "@saleor/app-sdk/APL";
|
||||
import { APL, FileAPL, RedisAPL, SaleorCloudAPL, UpstashAPL } from "@saleor/app-sdk/APL";
|
||||
import { SaleorApp } from "@saleor/app-sdk/saleor-app";
|
||||
|
||||
const aplType = process.env.APL ?? "file";
|
||||
|
@ -6,6 +6,12 @@ const aplType = process.env.APL ?? "file";
|
|||
export let apl: APL;
|
||||
|
||||
switch (aplType) {
|
||||
case "redis": {
|
||||
if (!process.env.REDIS_URL) throw new Error("Missing redis url");
|
||||
if (!process.env.APP_API_BASE_URL)
|
||||
throw new Error("Redis relies on APP_API_BASE_URL to store keys, please set env variable");
|
||||
apl = new RedisAPL(new URL(process.env.REDIS_URL), process.env.APP_API_BASE_URL);
|
||||
}
|
||||
case "upstash":
|
||||
apl = new UpstashAPL();
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"extends": ["//"],
|
||||
"extends": [
|
||||
"//"
|
||||
],
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"pipeline": {
|
||||
"build": {
|
||||
|
@ -21,7 +23,8 @@
|
|||
"NEXT_PUBLIC_SENTRY_DSN",
|
||||
"SENTRY_ENVIRONMENT",
|
||||
"APP_IFRAME_BASE_URL",
|
||||
"APP_API_BASE_URL"
|
||||
"APP_API_BASE_URL",
|
||||
"REDIS_URL"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
# saleor-app-products-feed
|
||||
|
||||
## 1.12.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ae6dbb1: Removed webhooks on product changes used for feed cache due to changed max execution time.
|
||||
- ae6dbb1: Changed Vercel's maximum execution time to be 5 minutes for feed generation. This should help with the previous limits of 60s, that was not enough for feed to be generated.
|
||||
|
||||
## 1.12.1
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
fragment ProductVariantWebhookPayload on ProductVariant {
|
||||
channel
|
||||
channelListings {
|
||||
channel {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
fragment ProductWebhookPayload on Product {
|
||||
channel
|
||||
channelListings {
|
||||
channel {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
subscription ProductCreated {
|
||||
event {
|
||||
... on ProductCreated {
|
||||
product {
|
||||
...ProductWebhookPayload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
subscription ProductDeleted {
|
||||
event {
|
||||
... on ProductDeleted {
|
||||
product {
|
||||
...ProductWebhookPayload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
subscription ProductUpdated {
|
||||
event {
|
||||
... on ProductUpdated {
|
||||
product {
|
||||
...ProductWebhookPayload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
subscription ProductVariantCreated {
|
||||
event {
|
||||
... on ProductVariantCreated {
|
||||
productVariant {
|
||||
...ProductVariantWebhookPayload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
subscription ProductVariantDeleted {
|
||||
event {
|
||||
... on ProductVariantDeleted {
|
||||
productVariant {
|
||||
...ProductVariantWebhookPayload
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
subscription ProductVariantUpdated {
|
||||
event {
|
||||
... on ProductVariantUpdated {
|
||||
productVariant {
|
||||
...ProductVariantWebhookPayload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,12 @@ const isSentryPropertiesInEnvironment =
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
transpilePackages: ["@saleor/apps-shared", "@saleor/apps-ui", "@saleor/react-hook-form-macaw"],
|
||||
transpilePackages: [
|
||||
"@saleor/apps-shared",
|
||||
"@saleor/apps-ui",
|
||||
"@saleor/react-hook-form-macaw",
|
||||
"@saleor/webhook-utils",
|
||||
],
|
||||
};
|
||||
|
||||
const configWithSentry = withSentryConfig(
|
||||
|
@ -22,7 +27,7 @@ const configWithSentry = withSentryConfig(
|
|||
tunnelRoute: "/monitoring",
|
||||
hideSourceMaps: true,
|
||||
disableLogger: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
module.exports = isSentryPropertiesInEnvironment ? configWithSentry : nextConfig;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "saleor-app-products-feed",
|
||||
"version": "1.12.1",
|
||||
"version": "1.12.2",
|
||||
"scripts": {
|
||||
"build": "pnpm generate && next build",
|
||||
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
||||
|
@ -19,6 +19,7 @@
|
|||
"@saleor/apps-ui": "workspace:*",
|
||||
"@saleor/macaw-ui": "0.8.0-pre.127",
|
||||
"@saleor/react-hook-form-macaw": "workspace:*",
|
||||
"@saleor/webhook-utils": "workspace:*",
|
||||
"@sentry/nextjs": "7.67.0",
|
||||
"@tanstack/react-query": "4.29.19",
|
||||
"@trpc/client": "10.38.1",
|
||||
|
@ -27,6 +28,7 @@
|
|||
"@trpc/server": "10.38.1",
|
||||
"@urql/exchange-auth": "^2.1.4",
|
||||
"@vitejs/plugin-react": "4.0.4",
|
||||
"dotenv": "^16.3.1",
|
||||
"fast-xml-parser": "^4.0.15",
|
||||
"graphql": "16.7.1",
|
||||
"graphql-tag": "^2.12.6",
|
||||
|
|
7
apps/products-feed/scripts/migrations/README.md
Normal file
7
apps/products-feed/scripts/migrations/README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Webhook migration scripts
|
||||
|
||||
Test migration with dry run, operation will not modify any data:
|
||||
`npx tsx scripts/migrations/run-webhooks-migration-dry-run.ts`
|
||||
|
||||
To start the migration run command:
|
||||
`npx tsx scripts/migrations/run-webhooks-migration.ts`
|
20
apps/products-feed/scripts/migrations/migration-utils.ts
Normal file
20
apps/products-feed/scripts/migrations/migration-utils.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
|
||||
import { SaleorCloudAPL } from "@saleor/app-sdk/APL";
|
||||
|
||||
export const verifyRequiredEnvs = () => {
|
||||
const requiredEnvs = ["SALEOR_CLOUD_TOKEN", "SALEOR_CLOUD_RESOURCE_URL"];
|
||||
|
||||
if (!requiredEnvs.every((env) => process.env[env])) {
|
||||
throw new Error(`Missing envs: ${requiredEnvs.join(" | ")}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const fetchCloudAplEnvs = () => {
|
||||
const saleorAPL = new SaleorCloudAPL({
|
||||
token: process.env.SALEOR_CLOUD_TOKEN!,
|
||||
resourceUrl: process.env.SALEOR_CLOUD_RESOURCE_URL!,
|
||||
});
|
||||
|
||||
return saleorAPL.getAll();
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
|
||||
import * as dotenv from "dotenv";
|
||||
import { fetchCloudAplEnvs, verifyRequiredEnvs } from "./migration-utils";
|
||||
import { updateWebhooksScript } from "./update-webhooks";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const runMigration = async () => {
|
||||
console.log("Starting webhooks migration (dry run)");
|
||||
|
||||
verifyRequiredEnvs();
|
||||
|
||||
console.log("Envs verified, fetching envs");
|
||||
|
||||
const allEnvs = await fetchCloudAplEnvs().catch((r) => {
|
||||
console.error("Could not fetch instances from the APL");
|
||||
console.error(r);
|
||||
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
for (const env of allEnvs) {
|
||||
await updateWebhooksScript({ authData: env, dryRun: true });
|
||||
}
|
||||
|
||||
console.log("Migration dry run complete");
|
||||
};
|
||||
|
||||
runMigration();
|
|
@ -0,0 +1,30 @@
|
|||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
|
||||
import * as dotenv from "dotenv";
|
||||
import { fetchCloudAplEnvs, verifyRequiredEnvs } from "./migration-utils";
|
||||
import { updateWebhooksScript } from "./update-webhooks";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const runMigration = async () => {
|
||||
console.log("Starting running migration");
|
||||
|
||||
verifyRequiredEnvs();
|
||||
|
||||
console.log("Envs verified, fetching envs");
|
||||
|
||||
const allEnvs = await fetchCloudAplEnvs().catch((r) => {
|
||||
console.error("Could not fetch instances from the APL");
|
||||
console.error(r);
|
||||
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
for (const env of allEnvs) {
|
||||
await updateWebhooksScript({ authData: env, dryRun: false });
|
||||
}
|
||||
|
||||
console.log("Migration complete");
|
||||
};
|
||||
|
||||
runMigration();
|
29
apps/products-feed/scripts/migrations/update-webhooks.ts
Normal file
29
apps/products-feed/scripts/migrations/update-webhooks.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
|
||||
import { createGraphQLClient } from "@saleor/apps-shared";
|
||||
import { AuthData } from "@saleor/app-sdk/APL";
|
||||
import { webhookMigrationRunner } from "@saleor/webhook-utils";
|
||||
|
||||
export const updateWebhooksScript = async ({
|
||||
authData,
|
||||
dryRun,
|
||||
}: {
|
||||
authData: AuthData;
|
||||
dryRun: boolean;
|
||||
}) => {
|
||||
console.log("Working on env: ", authData.saleorApiUrl);
|
||||
|
||||
const client = createGraphQLClient({
|
||||
saleorApiUrl: authData.saleorApiUrl,
|
||||
token: authData.token,
|
||||
});
|
||||
|
||||
await webhookMigrationRunner({
|
||||
client,
|
||||
dryRun,
|
||||
getManifests: async ({ appDetails }) => {
|
||||
// Products feed application has currently no webhooks, so we return empty array
|
||||
return [];
|
||||
},
|
||||
});
|
||||
};
|
|
@ -2,7 +2,6 @@ import { router } from "../trpc/trpc-server";
|
|||
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
|
||||
import { updateCacheForConfigurations } from "../metadata-cache/update-cache-for-configurations";
|
||||
import { AppConfigSchema, imageSizeInputSchema, titleTemplateInputSchema } from "./app-config";
|
||||
import { z } from "zod";
|
||||
import { createS3ClientFromConfiguration } from "../file-storage/s3/create-s3-client-from-configuration";
|
||||
|
@ -106,17 +105,6 @@ export const appConfigurationRouter = router({
|
|||
}) => {
|
||||
const config = await getConfig();
|
||||
|
||||
/**
|
||||
* TODO Check if this has to run, once its cached, it should be invalidated by webhooks only.
|
||||
*
|
||||
* But this operation isn't expensive and users will not continuously save this form
|
||||
*/
|
||||
await updateCacheForConfigurations({
|
||||
client: apiClient,
|
||||
channelsSlugs: [input.channelSlug],
|
||||
saleorApiUrl: saleorApiUrl,
|
||||
});
|
||||
|
||||
logger.debug({ channel: input.channelSlug }, "Updated cache for channel");
|
||||
|
||||
config.setChannelUrls(input.channelSlug, input.urls);
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
import { SettingsManager } from "@saleor/app-sdk/settings-manager";
|
||||
|
||||
export class CacheConfigurator {
|
||||
private metadataKeyPrefix = "cursor-cache-";
|
||||
|
||||
constructor(private metadataManager: SettingsManager, private saleorApiUrl: string) {}
|
||||
|
||||
private constructKey(channel: string) {
|
||||
return this.metadataKeyPrefix + channel;
|
||||
}
|
||||
|
||||
get({ channel }: { channel: string }): Promise<string[] | undefined> {
|
||||
return this.metadataManager.get(this.constructKey(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.constructKey(channel),
|
||||
value: JSON.stringify(value),
|
||||
domain: this.saleorApiUrl,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
import { createLogger } from "@saleor/apps-shared";
|
||||
import { CacheConfigurator } from "./cache-configurator";
|
||||
import { createSettingsManager } from "../../lib/metadata-manager";
|
||||
import { getCursors } from "../google-feed/fetch-product-data";
|
||||
import { Client } from "urql";
|
||||
|
||||
interface UpdateCacheForConfigurationsArgs {
|
||||
client: Client;
|
||||
saleorApiUrl: string;
|
||||
channelsSlugs: string[];
|
||||
}
|
||||
|
||||
export const updateCacheForConfigurations = async ({
|
||||
client,
|
||||
channelsSlugs,
|
||||
saleorApiUrl,
|
||||
}: UpdateCacheForConfigurationsArgs) => {
|
||||
const logger = createLogger({ saleorApiUrl: saleorApiUrl });
|
||||
|
||||
logger.debug("Updating the cursor cache");
|
||||
|
||||
const cache = new CacheConfigurator(createSettingsManager(client), saleorApiUrl);
|
||||
|
||||
const cacheUpdatePromises = channelsSlugs.map(async (channel) => {
|
||||
const cursors = await getCursors({ client, channel });
|
||||
|
||||
await cache.set({ channel, value: cursors });
|
||||
});
|
||||
|
||||
await Promise.all(cacheUpdatePromises);
|
||||
|
||||
logger.debug("Cursor cache updated");
|
||||
};
|
|
@ -1,41 +0,0 @@
|
|||
import { GraphqlClientFactory } from "../../lib/create-graphql-client";
|
||||
import { updateCacheForConfigurations } from "./update-cache-for-configurations";
|
||||
import { AuthData } from "@saleor/app-sdk/APL";
|
||||
import {
|
||||
ProductVariantWebhookPayloadFragment,
|
||||
ProductWebhookPayloadFragment,
|
||||
} from "../../../generated/graphql";
|
||||
import { NextApiResponse } from "next";
|
||||
|
||||
type ChannelFragment =
|
||||
| Pick<ProductWebhookPayloadFragment, "channel" | "channelListings">
|
||||
| Pick<ProductVariantWebhookPayloadFragment, "channel" | "channelListings">;
|
||||
|
||||
export const updateCacheOnWebhook = async ({
|
||||
channels,
|
||||
authData,
|
||||
res,
|
||||
}: {
|
||||
authData: AuthData;
|
||||
channels: ChannelFragment;
|
||||
res: NextApiResponse;
|
||||
}) => {
|
||||
const client = GraphqlClientFactory.fromAuthData(authData);
|
||||
|
||||
const channelsSlugs = [
|
||||
channels.channel,
|
||||
...(channels.channelListings?.map((cl) => cl.channel.slug) ?? []),
|
||||
].filter((c) => c) as string[];
|
||||
|
||||
if (channelsSlugs.length === 0) {
|
||||
return res.status(200).end();
|
||||
}
|
||||
|
||||
await updateCacheForConfigurations({
|
||||
channelsSlugs,
|
||||
client,
|
||||
saleorApiUrl: authData.saleorApiUrl,
|
||||
});
|
||||
|
||||
return res.status(200).end();
|
||||
};
|
|
@ -6,9 +6,6 @@ import { fetchProductData } from "../../../../../modules/google-feed/fetch-produ
|
|||
import { GoogleFeedSettingsFetcher } from "../../../../../modules/google-feed/get-google-feed-settings";
|
||||
import { generateGoogleXmlFeed } from "../../../../../modules/google-feed/generate-google-xml-feed";
|
||||
import { fetchShopData } from "../../../../../modules/google-feed/fetch-shop-data";
|
||||
import { CacheConfigurator } from "../../../../../modules/metadata-cache/cache-configurator";
|
||||
import { createSettingsManager } from "../../../../../lib/metadata-manager";
|
||||
import { GraphqlClientFactory } from "../../../../../lib/create-graphql-client";
|
||||
import { uploadFile } from "../../../../../modules/file-storage/s3/upload-file";
|
||||
import { createS3ClientFromConfiguration } from "../../../../../modules/file-storage/s3/create-s3-client-from-configuration";
|
||||
import { getFileDetails } from "../../../../../modules/file-storage/s3/get-file-details";
|
||||
|
@ -16,6 +13,10 @@ import { getDownloadUrl, getFileName } from "../../../../../modules/file-storage
|
|||
import { RootConfig } from "../../../../../modules/app-configuration/app-config";
|
||||
import { z, ZodError } from "zod";
|
||||
|
||||
export const config = {
|
||||
maxDuration: 5 * 60, // 5 minutes
|
||||
};
|
||||
|
||||
// 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
|
||||
? parseInt(process.env.FEED_CACHE_MAX_AGE, 10)
|
||||
|
@ -157,23 +158,10 @@ export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
|
||||
logger.debug("Generating a new feed");
|
||||
|
||||
const cacheClient = GraphqlClientFactory.fromAuthData(authData);
|
||||
|
||||
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, cursors, imageSize });
|
||||
productVariants = await fetchProductData({ client, channel, imageSize });
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return res.status(400).end();
|
||||
|
|
|
@ -2,11 +2,6 @@ import { createManifestHandler } from "@saleor/app-sdk/handlers/next";
|
|||
import { AppManifest } from "@saleor/app-sdk/types";
|
||||
|
||||
import packageJson from "../../../package.json";
|
||||
import { webhookProductCreated } from "./webhooks/product_created";
|
||||
import { webhookProductDeleted } from "./webhooks/product_deleted";
|
||||
import { webhookProductVariantCreated } from "./webhooks/product_variant_created";
|
||||
import { webhookProductVariantDeleted } from "./webhooks/product_variant_deleted";
|
||||
import { webhookProductVariantUpdated } from "./webhooks/product_variant_updated";
|
||||
|
||||
export default createManifestHandler({
|
||||
async manifestFactory({ appBaseUrl }) {
|
||||
|
@ -31,13 +26,7 @@ export default createManifestHandler({
|
|||
supportUrl: "https://github.com/saleor/apps/discussions",
|
||||
tokenTargetUrl: `${apiBaseURL}/api/register`,
|
||||
version: packageJson.version,
|
||||
webhooks: [
|
||||
webhookProductCreated.getWebhookManifest(apiBaseURL),
|
||||
webhookProductDeleted.getWebhookManifest(apiBaseURL),
|
||||
webhookProductVariantCreated.getWebhookManifest(apiBaseURL),
|
||||
webhookProductVariantDeleted.getWebhookManifest(apiBaseURL),
|
||||
webhookProductVariantUpdated.getWebhookManifest(apiBaseURL),
|
||||
],
|
||||
webhooks: [],
|
||||
};
|
||||
|
||||
return manifest;
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import { saleorApp } from "../../../saleor-app";
|
||||
import {
|
||||
ProductCreatedDocument,
|
||||
ProductWebhookPayloadFragment,
|
||||
} from "../../../../generated/graphql";
|
||||
import { updateCacheOnWebhook } from "../../../modules/metadata-cache/update-cache-on-webhook";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const webhookProductCreated = new SaleorAsyncWebhook<ProductWebhookPayloadFragment>({
|
||||
webhookPath: "api/webhooks/product_created",
|
||||
event: "PRODUCT_CREATED",
|
||||
apl: saleorApp.apl,
|
||||
query: ProductCreatedDocument,
|
||||
// todo make it disabled by default, enable when app is configured
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
const logger = createLogger({
|
||||
service: "webhook-product_created",
|
||||
});
|
||||
|
||||
export const handler: NextWebhookApiHandler<ProductWebhookPayloadFragment> = async (
|
||||
req,
|
||||
res,
|
||||
context
|
||||
) => {
|
||||
await updateCacheOnWebhook({
|
||||
authData: context.authData,
|
||||
channels: context.payload,
|
||||
res,
|
||||
});
|
||||
};
|
||||
|
||||
export default webhookProductCreated.createHandler(handler);
|
|
@ -1,40 +0,0 @@
|
|||
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
|
||||
import {
|
||||
ProductDeletedDocument,
|
||||
ProductWebhookPayloadFragment,
|
||||
} from "../../../../generated/graphql";
|
||||
import { saleorApp } from "../../../saleor-app";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import { updateCacheOnWebhook } from "../../../modules/metadata-cache/update-cache-on-webhook";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const webhookProductDeleted = new SaleorAsyncWebhook<ProductWebhookPayloadFragment>({
|
||||
webhookPath: "api/webhooks/product_deleted",
|
||||
event: "PRODUCT_DELETED",
|
||||
apl: saleorApp.apl,
|
||||
query: ProductDeletedDocument,
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
const logger = createLogger({
|
||||
service: "webhook_product_deleted",
|
||||
});
|
||||
|
||||
export const handler: NextWebhookApiHandler<ProductWebhookPayloadFragment> = async (
|
||||
req,
|
||||
res,
|
||||
context
|
||||
) => {
|
||||
await updateCacheOnWebhook({
|
||||
authData: context.authData,
|
||||
channels: context.payload,
|
||||
res,
|
||||
});
|
||||
};
|
||||
|
||||
export default webhookProductDeleted.createHandler(handler);
|
|
@ -1,40 +0,0 @@
|
|||
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
|
||||
import {
|
||||
ProductUpdatedDocument,
|
||||
ProductWebhookPayloadFragment,
|
||||
} from "../../../../generated/graphql";
|
||||
import { saleorApp } from "../../../saleor-app";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import { updateCacheOnWebhook } from "../../../modules/metadata-cache/update-cache-on-webhook";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const webhookProductUpdated = new SaleorAsyncWebhook<ProductWebhookPayloadFragment>({
|
||||
webhookPath: "api/webhooks/product_updated",
|
||||
event: "PRODUCT_UPDATED",
|
||||
apl: saleorApp.apl,
|
||||
query: ProductUpdatedDocument,
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
const logger = createLogger({
|
||||
service: "webhookProductUpdatedWebhookHandler",
|
||||
});
|
||||
|
||||
export const handler: NextWebhookApiHandler<ProductWebhookPayloadFragment> = async (
|
||||
req,
|
||||
res,
|
||||
context
|
||||
) => {
|
||||
await updateCacheOnWebhook({
|
||||
authData: context.authData,
|
||||
channels: context.payload,
|
||||
res,
|
||||
});
|
||||
};
|
||||
|
||||
export default webhookProductUpdated.createHandler(handler);
|
|
@ -1,41 +0,0 @@
|
|||
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
|
||||
import {
|
||||
ProductVariantCreatedDocument,
|
||||
ProductVariantWebhookPayloadFragment,
|
||||
} from "../../../../generated/graphql";
|
||||
import { saleorApp } from "../../../saleor-app";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import { updateCacheOnWebhook } from "../../../modules/metadata-cache/update-cache-on-webhook";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const webhookProductVariantCreated =
|
||||
new SaleorAsyncWebhook<ProductVariantWebhookPayloadFragment>({
|
||||
webhookPath: "api/webhooks/product_variant_created",
|
||||
event: "PRODUCT_VARIANT_CREATED",
|
||||
apl: saleorApp.apl,
|
||||
query: ProductVariantCreatedDocument,
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
const logger = createLogger({
|
||||
service: "PRODUCT_VARIANT_CREATED webhook",
|
||||
});
|
||||
|
||||
export const handler: NextWebhookApiHandler<ProductVariantWebhookPayloadFragment> = async (
|
||||
req,
|
||||
res,
|
||||
context
|
||||
) => {
|
||||
await updateCacheOnWebhook({
|
||||
authData: context.authData,
|
||||
channels: context.payload,
|
||||
res,
|
||||
});
|
||||
};
|
||||
|
||||
export default webhookProductVariantCreated.createHandler(handler);
|
|
@ -1,41 +0,0 @@
|
|||
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import {
|
||||
ProductVariantDeletedDocument,
|
||||
ProductVariantWebhookPayloadFragment,
|
||||
} from "../../../../generated/graphql";
|
||||
import { saleorApp } from "../../../saleor-app";
|
||||
import { updateCacheOnWebhook } from "../../../modules/metadata-cache/update-cache-on-webhook";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const webhookProductVariantDeleted =
|
||||
new SaleorAsyncWebhook<ProductVariantWebhookPayloadFragment>({
|
||||
webhookPath: "api/webhooks/product_variant_deleted",
|
||||
event: "PRODUCT_VARIANT_DELETED",
|
||||
apl: saleorApp.apl,
|
||||
query: ProductVariantDeletedDocument,
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
const logger = createLogger({
|
||||
service: "PRODUCT_VARIANT_DELETED",
|
||||
});
|
||||
|
||||
export const handler: NextWebhookApiHandler<ProductVariantWebhookPayloadFragment> = async (
|
||||
req,
|
||||
res,
|
||||
context
|
||||
) => {
|
||||
await updateCacheOnWebhook({
|
||||
authData: context.authData,
|
||||
channels: context.payload,
|
||||
res,
|
||||
});
|
||||
};
|
||||
|
||||
export default webhookProductVariantDeleted.createHandler(handler);
|
|
@ -1,41 +0,0 @@
|
|||
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
|
||||
import { createLogger } from "@saleor/apps-shared";
|
||||
import {
|
||||
ProductVariantUpdatedDocument,
|
||||
ProductVariantWebhookPayloadFragment,
|
||||
} from "../../../../generated/graphql";
|
||||
import { saleorApp } from "../../../saleor-app";
|
||||
import { updateCacheOnWebhook } from "../../../modules/metadata-cache/update-cache-on-webhook";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const webhookProductVariantUpdated =
|
||||
new SaleorAsyncWebhook<ProductVariantWebhookPayloadFragment>({
|
||||
webhookPath: "api/webhooks/product_variant_updated",
|
||||
event: "PRODUCT_VARIANT_UPDATED",
|
||||
apl: saleorApp.apl,
|
||||
query: ProductVariantUpdatedDocument,
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
const logger = createLogger({
|
||||
service: "webhookProductVariantUpdatedWebhookHandler",
|
||||
});
|
||||
|
||||
export const handler: NextWebhookApiHandler<ProductVariantWebhookPayloadFragment> = async (
|
||||
req,
|
||||
res,
|
||||
context
|
||||
) => {
|
||||
await updateCacheOnWebhook({
|
||||
authData: context.authData,
|
||||
channels: context.payload,
|
||||
res,
|
||||
});
|
||||
};
|
||||
|
||||
export default webhookProductVariantUpdated.createHandler(handler);
|
|
@ -923,6 +923,9 @@ importers:
|
|||
'@saleor/react-hook-form-macaw':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/react-hook-form-macaw
|
||||
'@saleor/webhook-utils':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/webhook-utils
|
||||
'@sentry/nextjs':
|
||||
specifier: 7.67.0
|
||||
version: 7.67.0(next@13.4.8)(react@18.2.0)
|
||||
|
@ -947,6 +950,9 @@ importers:
|
|||
'@vitejs/plugin-react':
|
||||
specifier: 4.0.4
|
||||
version: 4.0.4(vite@4.4.8)
|
||||
dotenv:
|
||||
specifier: ^16.3.1
|
||||
version: 16.3.1
|
||||
fast-xml-parser:
|
||||
specifier: ^4.0.15
|
||||
version: 4.0.15
|
||||
|
|
Loading…
Reference in a new issue