Apply recent ESLint rules on the codebase (#404)
* Add lint:fix script * Reformat CRM app with eslint fix * Apply eslint fix on data importer codebase * Apply eslint fix on Invoices codebase * Apply eslint fix on Klaviyo codebase * Apply eslint fix on products-feed codebase * Apply eslint fix on monitoring codebase * Apply eslint fix on Search codebase * Apply eslint fix on Slack codebase * cleanup
This commit is contained in:
parent
57f6d41bc4
commit
2c0df91351
96 changed files with 612 additions and 364 deletions
16
.changeset/chilly-crabs-promise.md
Normal file
16
.changeset/chilly-crabs-promise.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
"saleor-app-emails-and-messages": patch
|
||||||
|
"saleor-app-data-importer": patch
|
||||||
|
"saleor-app-products-feed": patch
|
||||||
|
"saleor-app-monitoring": patch
|
||||||
|
"@saleor/apps-shared": patch
|
||||||
|
"saleor-app-invoices": patch
|
||||||
|
"saleor-app-klaviyo": patch
|
||||||
|
"saleor-app-search": patch
|
||||||
|
"saleor-app-slack": patch
|
||||||
|
"saleor-app-taxes": patch
|
||||||
|
"saleor-app-cms": patch
|
||||||
|
"saleor-app-crm": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Added lint:fix script, so `eslint --fix` can be run deliberately
|
|
@ -7,6 +7,7 @@
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
|
@ -63,9 +64,5 @@
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"typescript": "4.9",
|
"typescript": "4.9",
|
||||||
"vitest": "^0.30.1"
|
"vitest": "^0.30.1"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
|
@ -65,9 +66,5 @@
|
||||||
"eslint-config-saleor": "workspace:*",
|
"eslint-config-saleor": "workspace:*",
|
||||||
"prettier": "^2.8.2",
|
"prettier": "^2.8.2",
|
||||||
"typescript": "4.9.4"
|
"typescript": "4.9.4"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,9 +90,11 @@ export async function mutateMetadata(
|
||||||
export const createSettingsManager = (
|
export const createSettingsManager = (
|
||||||
client: Pick<Client, "query" | "mutation">
|
client: Pick<Client, "query" | "mutation">
|
||||||
): SettingsManager => {
|
): SettingsManager => {
|
||||||
// EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
/*
|
||||||
// We recommend it for production, because all values are encrypted.
|
* EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
||||||
// If your use case require plain text values, you can use MetadataManager.
|
* We recommend it for production, because all values are encrypted.
|
||||||
|
* If your use case require plain text values, you can use MetadataManager.
|
||||||
|
*/
|
||||||
return new EncryptedMetadataManager({
|
return new EncryptedMetadataManager({
|
||||||
// Secret key should be randomly created for production and set as environment variable
|
// Secret key should be randomly created for production and set as environment variable
|
||||||
encryptionKey: process.env.SECRET_KEY!,
|
encryptionKey: process.env.SECRET_KEY!,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { createLogger } from "../../../../lib/logger";
|
||||||
|
|
||||||
export const getBaseUrl = (headers: { [name: string]: string | string[] | undefined }): string => {
|
export const getBaseUrl = (headers: { [name: string]: string | string[] | undefined }): string => {
|
||||||
const { host, "x-forwarded-proto": protocol = "http" } = headers;
|
const { host, "x-forwarded-proto": protocol = "http" } = headers;
|
||||||
|
|
||||||
return `${protocol}://${host}`;
|
return `${protocol}://${host}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { SALEOR_API_URL_HEADER, SALEOR_AUTHORIZATION_BEARER_HEADER } from "@sale
|
||||||
|
|
||||||
export const getBaseUrl = (headers: { [name: string]: string | string[] | undefined }): string => {
|
export const getBaseUrl = (headers: { [name: string]: string | string[] | undefined }): string => {
|
||||||
const { host, "x-forwarded-proto": protocol = "http" } = headers;
|
const { host, "x-forwarded-proto": protocol = "http" } = headers;
|
||||||
|
|
||||||
return `${protocol}://${host}`;
|
return `${protocol}://${host}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ const handler: NextApiHandler = async (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const redirectUri = `${getBaseUrl(req.headers)}/api/auth/mailchimp/callback`;
|
const redirectUri = `${getBaseUrl(req.headers)}/api/auth/mailchimp/callback`;
|
||||||
|
|
||||||
logger.debug({ redirectUri }, "Resolved redirect uri");
|
logger.debug({ redirectUri }, "Resolved redirect uri");
|
||||||
|
|
||||||
const qs = new URLSearchParams({
|
const qs = new URLSearchParams({
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// This file sets a custom webpack configuration to use your Next.js app
|
/*
|
||||||
// with Sentry.
|
* This file sets a custom webpack configuration to use your Next.js app
|
||||||
// https://nextjs.org/docs/api-reference/next.config.js/introduction
|
* with Sentry.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
* https://nextjs.org/docs/api-reference/next.config.js/introduction
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
||||||
|
*/
|
||||||
const { withSentryConfig } = require("@sentry/nextjs");
|
const { withSentryConfig } = require("@sentry/nextjs");
|
||||||
|
|
||||||
const isSentryPropertiesInEnvironment =
|
const isSentryPropertiesInEnvironment =
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
|
@ -61,9 +62,5 @@
|
||||||
"eslint": "^8.33.0",
|
"eslint": "^8.33.0",
|
||||||
"eslint-config-saleor": "workspace:*",
|
"eslint-config-saleor": "workspace:*",
|
||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the browser.
|
/*
|
||||||
// The config you add here will be used whenever a page is visited.
|
* This file configures the initialization of Sentry on the browser.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever a page is visited.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever middleware or an Edge route handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever middleware or an Edge route handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever the server handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever the server handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -86,8 +86,10 @@ const generateAddressColumns = (labelNamespace: string, keyNamespace: string): C
|
||||||
// TODO - enable address columns when mapped
|
// TODO - enable address columns when mapped
|
||||||
const allColumns: ColumnAPI[] = [
|
const allColumns: ColumnAPI[] = [
|
||||||
...customerColumns,
|
...customerColumns,
|
||||||
// ...generateAddressColumns("Default Billing Address", "defaultBillingAddress"),
|
/*
|
||||||
// ...generateAddressColumns("Default Shipping Address", "defaultShippingAddress"),
|
* ...generateAddressColumns("Default Billing Address", "defaultBillingAddress"),
|
||||||
|
* ...generateAddressColumns("Default Shipping Address", "defaultShippingAddress"),
|
||||||
|
*/
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getCustomersModelColumns = () => allColumns;
|
export const getCustomersModelColumns = () => allColumns;
|
||||||
|
@ -116,8 +118,10 @@ export const getResultModelSchema = () =>
|
||||||
email: z.string(),
|
email: z.string(),
|
||||||
note: z.string().nullish(),
|
note: z.string().nullish(),
|
||||||
externalReference: z.string().nullish(),
|
externalReference: z.string().nullish(),
|
||||||
// defaultBillingAddress: zodAddressSchema,
|
/*
|
||||||
// defaultShippingAddress: zodAddressSchema,
|
* defaultBillingAddress: zodAddressSchema,
|
||||||
|
* defaultShippingAddress: zodAddressSchema,
|
||||||
|
*/
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ function NextApp({ Component, pageProps }: AppProps) {
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const jssStyles = document.querySelector("#jss-server-side");
|
const jssStyles = document.querySelector("#jss-server-side");
|
||||||
|
|
||||||
if (jssStyles) {
|
if (jssStyles) {
|
||||||
jssStyles?.parentElement?.removeChild(jssStyles);
|
jssStyles?.parentElement?.removeChild(jssStyles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,16 +20,20 @@ import * as Sentry from "@sentry/nextjs";
|
||||||
import NextErrorComponent from "next/error";
|
import NextErrorComponent from "next/error";
|
||||||
|
|
||||||
const CustomErrorComponent = (props) => {
|
const CustomErrorComponent = (props) => {
|
||||||
// If you're using a Nextjs version prior to 12.2.1, uncomment this to
|
/*
|
||||||
// compensate for https://github.com/vercel/next.js/issues/8592
|
* If you're using a Nextjs version prior to 12.2.1, uncomment this to
|
||||||
// Sentry.captureUnderscoreErrorException(props);
|
* compensate for https://github.com/vercel/next.js/issues/8592
|
||||||
|
* Sentry.captureUnderscoreErrorException(props);
|
||||||
|
*/
|
||||||
|
|
||||||
return <NextErrorComponent statusCode={props.statusCode} />;
|
return <NextErrorComponent statusCode={props.statusCode} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
CustomErrorComponent.getInitialProps = async (contextData) => {
|
CustomErrorComponent.getInitialProps = async (contextData) => {
|
||||||
// In case this is running in a serverless function, await this in order to give Sentry
|
/*
|
||||||
// time to send the error before the lambda exits
|
* In case this is running in a serverless function, await this in order to give Sentry
|
||||||
|
* time to send the error before the lambda exits
|
||||||
|
*/
|
||||||
await Sentry.captureUnderscoreErrorException(contextData);
|
await Sentry.captureUnderscoreErrorException(contextData);
|
||||||
|
|
||||||
// This will contain the status code of the response
|
// This will contain the status code of the response
|
||||||
|
|
|
@ -16,7 +16,11 @@
|
||||||
"REST_APL_TOKEN",
|
"REST_APL_TOKEN",
|
||||||
"NEXT_PUBLIC_VERCEL_ENV",
|
"NEXT_PUBLIC_VERCEL_ENV",
|
||||||
"VERCEL_URL",
|
"VERCEL_URL",
|
||||||
"PORT"
|
"PORT",
|
||||||
|
"SENTRY_AUTH_TOKEN",
|
||||||
|
"SENTRY_PROJECT",
|
||||||
|
"SENTRY_ORG",
|
||||||
|
"SENTRY_DSN"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "pnpm generate && prettier --loglevel warn --write . && eslint --fix .",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
|
@ -78,9 +79,5 @@
|
||||||
"eslint-config-saleor": "workspace:*",
|
"eslint-config-saleor": "workspace:*",
|
||||||
"prettier": "^2.8.2",
|
"prettier": "^2.8.2",
|
||||||
"typescript": "4.9.4"
|
"typescript": "4.9.4"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// This file sets a custom webpack configuration to use your Next.js app
|
/*
|
||||||
// with Sentry.
|
* This file sets a custom webpack configuration to use your Next.js app
|
||||||
// https://nextjs.org/docs/api-reference/next.config.js/introduction
|
* with Sentry.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* https://nextjs.org/docs/api-reference/next.config.js/introduction
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
const { withSentryConfig } = require("@sentry/nextjs");
|
const { withSentryConfig } = require("@sentry/nextjs");
|
||||||
|
|
||||||
|
@ -13,12 +15,14 @@ const isSentryPropertiesInEnvironment =
|
||||||
*/
|
*/
|
||||||
const moduleExports = {
|
const moduleExports = {
|
||||||
sentry: {
|
sentry: {
|
||||||
// Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
|
/*
|
||||||
// for client-side builds. (This will be the default starting in
|
* Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
|
||||||
// `@sentry/nextjs` version 8.0.0.) See
|
* for client-side builds. (This will be the default starting in
|
||||||
// https://webpack.js.org/configuration/devtool/ and
|
* `@sentry/nextjs` version 8.0.0.) See
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
|
* https://webpack.js.org/configuration/devtool/ and
|
||||||
// for more information.
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
|
||||||
|
* for more information.
|
||||||
|
*/
|
||||||
hideSourceMaps: true,
|
hideSourceMaps: true,
|
||||||
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
|
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
|
||||||
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
|
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
|
||||||
|
@ -31,17 +35,23 @@ const moduleExports = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const sentryWebpackPluginOptions = {
|
const sentryWebpackPluginOptions = {
|
||||||
// Additional config options for the Sentry Webpack plugin. Keep in mind that
|
/*
|
||||||
// the following options are set automatically, and overriding them is not
|
* Additional config options for the Sentry Webpack plugin. Keep in mind that
|
||||||
// recommended:
|
* the following options are set automatically, and overriding them is not
|
||||||
// release, url, org, project, authToken, configFile, stripPrefix,
|
* recommended:
|
||||||
// urlPrefix, include, ignore
|
* release, url, org, project, authToken, configFile, stripPrefix,
|
||||||
|
* urlPrefix, include, ignore
|
||||||
|
*/
|
||||||
|
|
||||||
silent: true, // Suppresses all logs
|
silent: true, // Suppresses all logs
|
||||||
// For all available options, see:
|
/*
|
||||||
// https://github.com/getsentry/sentry-webpack-plugin#options.
|
* For all available options, see:
|
||||||
|
* https://github.com/getsentry/sentry-webpack-plugin#options.
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure adding Sentry options is the last code to run before exporting, to
|
/*
|
||||||
// ensure that your source maps include changes from all other Webpack plugins
|
* Make sure adding Sentry options is the last code to run before exporting, to
|
||||||
|
* ensure that your source maps include changes from all other Webpack plugins
|
||||||
|
*/
|
||||||
module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);
|
module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
|
@ -71,9 +72,5 @@
|
||||||
"vite": "^4.2.1",
|
"vite": "^4.2.1",
|
||||||
"vitest": "^0.30.1",
|
"vitest": "^0.30.1",
|
||||||
"@types/semver": "^7.3.13"
|
"@types/semver": "^7.3.13"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the browser.
|
/*
|
||||||
// The config you add here will be used whenever a page is visited.
|
* This file configures the initialization of Sentry on the browser.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever a page is visited.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN;
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever middleware or an Edge route handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever middleware or an Edge route handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever the server handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever the server handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -81,9 +81,11 @@ export async function mutateMetadata(client: Client, metadata: MetadataEntry[])
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createSettingsManager = (client: Client) => {
|
export const createSettingsManager = (client: Client) => {
|
||||||
// EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
/*
|
||||||
// We recommend it for production, because all values are encrypted.
|
* EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
||||||
// If your use case require plain text values, you can use MetadataManager.
|
* We recommend it for production, because all values are encrypted.
|
||||||
|
* If your use case require plain text values, you can use MetadataManager.
|
||||||
|
*/
|
||||||
return new EncryptedMetadataManager({
|
return new EncryptedMetadataManager({
|
||||||
// Secret key should be randomly created for production and set as environment variable
|
// Secret key should be randomly created for production and set as environment variable
|
||||||
encryptionKey: process.env.SECRET_KEY!,
|
encryptionKey: process.env.SECRET_KEY!,
|
||||||
|
|
|
@ -19,13 +19,15 @@ export class MicroinvoiceInvoiceGenerator implements InvoiceGenerator {
|
||||||
|
|
||||||
const microinvoiceInstance = new Microinvoice({
|
const microinvoiceInstance = new Microinvoice({
|
||||||
style: {
|
style: {
|
||||||
// header: {
|
/*
|
||||||
// image: {
|
* header: {
|
||||||
// path: "./examples/logo.png",
|
* image: {
|
||||||
// width: 50,
|
* path: "./examples/logo.png",
|
||||||
// height: 19,
|
* width: 50,
|
||||||
// },
|
* height: 19,
|
||||||
// },
|
* },
|
||||||
|
* },
|
||||||
|
*/
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
invoice: {
|
invoice: {
|
||||||
|
@ -60,10 +62,12 @@ export class MicroinvoiceInvoiceGenerator implements InvoiceGenerator {
|
||||||
order.billingAddress?.country.country,
|
order.billingAddress?.country.country,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
/*
|
||||||
// label: "Tax Identifier",
|
* {
|
||||||
// value: "todo",
|
* label: "Tax Identifier",
|
||||||
// },
|
* value: "todo",
|
||||||
|
* },
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
|
|
||||||
seller: [
|
seller: [
|
||||||
|
@ -79,23 +83,27 @@ export class MicroinvoiceInvoiceGenerator implements InvoiceGenerator {
|
||||||
companyAddressData.countryArea,
|
companyAddressData.countryArea,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
/*
|
||||||
// label: "Tax Identifier",
|
* {
|
||||||
// value: "todo",
|
* label: "Tax Identifier",
|
||||||
// },
|
* value: "todo",
|
||||||
|
* },
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
|
|
||||||
legal: [
|
legal: [
|
||||||
// {
|
/*
|
||||||
// value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
|
* {
|
||||||
// weight: "bold",
|
* value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
|
||||||
// color: "primary",
|
* weight: "bold",
|
||||||
// },
|
* color: "primary",
|
||||||
// {
|
* },
|
||||||
// value: "sed do eiusmod tempor incididunt ut labore et dolore magna.",
|
* {
|
||||||
// weight: "bold",
|
* value: "sed do eiusmod tempor incididunt ut labore et dolore magna.",
|
||||||
// color: "secondary",
|
* weight: "bold",
|
||||||
// },
|
* color: "secondary",
|
||||||
|
* },
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
|
|
||||||
details: {
|
details: {
|
||||||
|
|
|
@ -22,6 +22,7 @@ function NextApp({ Component, pageProps }: AppProps) {
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const jssStyles = document.querySelector("#jss-server-side");
|
const jssStyles = document.querySelector("#jss-server-side");
|
||||||
|
|
||||||
if (jssStyles) {
|
if (jssStyles) {
|
||||||
jssStyles?.parentElement?.removeChild(jssStyles);
|
jssStyles?.parentElement?.removeChild(jssStyles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,16 +20,20 @@ import * as Sentry from '@sentry/nextjs';
|
||||||
import NextErrorComponent from 'next/error';
|
import NextErrorComponent from 'next/error';
|
||||||
|
|
||||||
const CustomErrorComponent = props => {
|
const CustomErrorComponent = props => {
|
||||||
// If you're using a Nextjs version prior to 12.2.1, uncomment this to
|
/*
|
||||||
// compensate for https://github.com/vercel/next.js/issues/8592
|
* If you're using a Nextjs version prior to 12.2.1, uncomment this to
|
||||||
// Sentry.captureUnderscoreErrorException(props);
|
* compensate for https://github.com/vercel/next.js/issues/8592
|
||||||
|
* Sentry.captureUnderscoreErrorException(props);
|
||||||
|
*/
|
||||||
|
|
||||||
return <NextErrorComponent statusCode={props.statusCode} />;
|
return <NextErrorComponent statusCode={props.statusCode} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
CustomErrorComponent.getInitialProps = async contextData => {
|
CustomErrorComponent.getInitialProps = async contextData => {
|
||||||
// In case this is running in a serverless function, await this in order to give Sentry
|
/*
|
||||||
// time to send the error before the lambda exits
|
* In case this is running in a serverless function, await this in order to give Sentry
|
||||||
|
* time to send the error before the lambda exits
|
||||||
|
*/
|
||||||
await Sentry.captureUnderscoreErrorException(contextData);
|
await Sentry.captureUnderscoreErrorException(contextData);
|
||||||
|
|
||||||
// This will contain the status code of the response
|
// This will contain the status code of the response
|
||||||
|
|
|
@ -174,6 +174,7 @@ export const handler: NextWebhookApiHandler<InvoiceRequestedPayloadFragment> = a
|
||||||
);
|
);
|
||||||
|
|
||||||
const hashedInvoiceName = hashInvoiceFilename(invoiceName, orderId);
|
const hashedInvoiceName = hashInvoiceFilename(invoiceName, orderId);
|
||||||
|
|
||||||
logger.debug({ hashedInvoiceName });
|
logger.debug({ hashedInvoiceName });
|
||||||
|
|
||||||
const hashedInvoiceFileName = `${hashedInvoiceName}.pdf`;
|
const hashedInvoiceFileName = `${hashedInvoiceName}.pdf`;
|
||||||
|
|
|
@ -14,7 +14,11 @@
|
||||||
"ALLOWED_DOMAIN_PATTERN",
|
"ALLOWED_DOMAIN_PATTERN",
|
||||||
"NEXT_PUBLIC_VERCEL_ENV",
|
"NEXT_PUBLIC_VERCEL_ENV",
|
||||||
"REST_APL_ENDPOINT",
|
"REST_APL_ENDPOINT",
|
||||||
"REST_APL_TOKEN"
|
"REST_APL_TOKEN",
|
||||||
|
"SENTRY_PROJECT",
|
||||||
|
"SENTRY_DSN",
|
||||||
|
"SENTRY_ORG",
|
||||||
|
"SENTRY_AUTH_TOKEN"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,17 +28,23 @@ const nextConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const sentryWebpackPluginOptions = {
|
const sentryWebpackPluginOptions = {
|
||||||
// Additional config options for the Sentry Webpack plugin. Keep in mind that
|
/*
|
||||||
// the following options are set automatically, and overriding them is not
|
* Additional config options for the Sentry Webpack plugin. Keep in mind that
|
||||||
// recommended:
|
* the following options are set automatically, and overriding them is not
|
||||||
// release, url, org, project, authToken, configFile, stripPrefix,
|
* recommended:
|
||||||
// urlPrefix, include, ignore
|
* release, url, org, project, authToken, configFile, stripPrefix,
|
||||||
|
* urlPrefix, include, ignore
|
||||||
|
*/
|
||||||
|
|
||||||
silent: true, // Suppresses all logs
|
silent: true, // Suppresses all logs
|
||||||
// For all available options, see:
|
/*
|
||||||
// https://github.com/getsentry/sentry-webpack-plugin#options.
|
* For all available options, see:
|
||||||
|
* https://github.com/getsentry/sentry-webpack-plugin#options.
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure adding Sentry options is the last code to run before exporting, to
|
/*
|
||||||
// ensure that your source maps include changes from all other Webpack plugins
|
* Make sure adding Sentry options is the last code to run before exporting, to
|
||||||
|
* ensure that your source maps include changes from all other Webpack plugins
|
||||||
|
*/
|
||||||
module.exports = withSentryConfig(nextConfig, sentryWebpackPluginOptions);
|
module.exports = withSentryConfig(nextConfig, sentryWebpackPluginOptions);
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "pnpm generate && prettier --loglevel warn --write . && eslint --fix .",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen"
|
"generate": "graphql-codegen"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// This file configures the initialization of Sentry on the browser.
|
/*
|
||||||
// The config you add here will be used whenever a page is visited.
|
* This file configures the initialization of Sentry on the browser.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever a page is visited.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
|
@ -10,8 +12,10 @@ Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever the server handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever the server handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
|
@ -10,8 +12,10 @@ Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,6 +39,7 @@ export const useAppApi = ({ url, options, skip }: UseFetchProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
|
|
||||||
setData(json);
|
setData(json);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(e as unknown);
|
setError(e as unknown);
|
||||||
|
|
|
@ -5,6 +5,7 @@ interface EmailServiceProvider {
|
||||||
export const Klaviyo = (token: string): EmailServiceProvider => ({
|
export const Klaviyo = (token: string): EmailServiceProvider => ({
|
||||||
send: async (event, recipient, context) => {
|
send: async (event, recipient, context) => {
|
||||||
const formParams = new URLSearchParams();
|
const formParams = new URLSearchParams();
|
||||||
|
|
||||||
formParams.append(
|
formParams.append(
|
||||||
"data",
|
"data",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
|
@ -8,10 +8,12 @@ import {
|
||||||
} from "../../generated/graphql";
|
} from "../../generated/graphql";
|
||||||
import { settingsManagerSecretKey } from "../../saleor-app";
|
import { settingsManagerSecretKey } from "../../saleor-app";
|
||||||
|
|
||||||
// Function is using urql graphql client to fetch all available metadata.
|
/*
|
||||||
// Before returning query result, we are transforming response to list of objects with key and value fields
|
* Function is using urql graphql client to fetch all available metadata.
|
||||||
// which can be used by the manager.
|
* Before returning query result, we are transforming response to list of objects with key and value fields
|
||||||
// Result of this query is cached by the manager.
|
* which can be used by the manager.
|
||||||
|
* Result of this query is cached by the manager.
|
||||||
|
*/
|
||||||
export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]> {
|
export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]> {
|
||||||
const { error, data } = await client
|
const { error, data } = await client
|
||||||
.query<FetchAppDetailsQuery>(FetchAppDetailsDocument, {})
|
.query<FetchAppDetailsQuery>(FetchAppDetailsDocument, {})
|
||||||
|
@ -25,9 +27,11 @@ export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]>
|
||||||
return data?.app?.privateMetadata.map((md) => ({ key: md.key, value: md.value })) || [];
|
return data?.app?.privateMetadata.map((md) => ({ key: md.key, value: md.value })) || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutate function takes urql client and metadata entries, and construct mutation to the API.
|
/*
|
||||||
// Before data are send, additional query for required App ID is made.
|
* Mutate function takes urql client and metadata entries, and construct mutation to the API.
|
||||||
// The manager will use updated entries returned by this mutation to update it's cache.
|
* Before data are send, additional query for required App ID is made.
|
||||||
|
* The manager will use updated entries returned by this mutation to update it's cache.
|
||||||
|
*/
|
||||||
export async function mutateMetadata(client: Client, appId: string, metadata: MetadataEntry[]) {
|
export async function mutateMetadata(client: Client, appId: string, metadata: MetadataEntry[]) {
|
||||||
const { error: mutationError, data: mutationData } = await client
|
const { error: mutationError, data: mutationData } = await client
|
||||||
.mutation(UpdateAppMetadataDocument, {
|
.mutation(UpdateAppMetadataDocument, {
|
||||||
|
@ -50,9 +54,11 @@ export async function mutateMetadata(client: Client, appId: string, metadata: Me
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createSettingsManager = (client: Client, appId: string) =>
|
export const createSettingsManager = (client: Client, appId: string) =>
|
||||||
// EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
/*
|
||||||
// We recommend it for production, because all values are encrypted.
|
* EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
||||||
// If your use case require plain text values, you can use MetadataManager.
|
* We recommend it for production, because all values are encrypted.
|
||||||
|
* If your use case require plain text values, you can use MetadataManager.
|
||||||
|
*/
|
||||||
new EncryptedMetadataManager({
|
new EncryptedMetadataManager({
|
||||||
// Secret key should be randomly created for production and set as environment variable
|
// Secret key should be randomly created for production and set as environment variable
|
||||||
encryptionKey: settingsManagerSecretKey,
|
encryptionKey: settingsManagerSecretKey,
|
||||||
|
|
|
@ -73,6 +73,7 @@ function SaleorApp({ Component, pageProps }: AppLayoutProps) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const jssStyles = document.querySelector("#jss-server-side");
|
const jssStyles = document.querySelector("#jss-server-side");
|
||||||
|
|
||||||
if (jssStyles) {
|
if (jssStyles) {
|
||||||
jssStyles?.parentElement?.removeChild(jssStyles);
|
jssStyles?.parentElement?.removeChild(jssStyles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,12 @@ interface AppErrorProps extends ErrorProps {
|
||||||
|
|
||||||
function MyError({ statusCode, hasGetInitialPropsRun, err }: ErrorPageProps) {
|
function MyError({ statusCode, hasGetInitialPropsRun, err }: ErrorPageProps) {
|
||||||
if (!hasGetInitialPropsRun && err) {
|
if (!hasGetInitialPropsRun && err) {
|
||||||
// getInitialProps is not called when an exception is thrown
|
/*
|
||||||
// at the top level of a module while it is being loaded.
|
* getInitialProps is not called when an exception is thrown
|
||||||
// As a workaround, we pass err via _app.js so it can be captured
|
* at the top level of a module while it is being loaded.
|
||||||
// Read more: https://github.com/vercel/next.js/issues/8592.
|
* As a workaround, we pass err via _app.js so it can be captured
|
||||||
|
* Read more: https://github.com/vercel/next.js/issues/8592.
|
||||||
|
*/
|
||||||
Sentry.captureException(err);
|
Sentry.captureException(err);
|
||||||
// Flushing is not required in this case as it only happens on the client
|
// Flushing is not required in this case as it only happens on the client
|
||||||
}
|
}
|
||||||
|
@ -31,8 +33,10 @@ MyError.getInitialProps = async (context: NextPageContext) => {
|
||||||
|
|
||||||
const { res, err, asPath } = context;
|
const { res, err, asPath } = context;
|
||||||
|
|
||||||
// Workaround for https://github.com/vercel/next.js/issues/8592, mark when
|
/*
|
||||||
// getInitialProps has run
|
* Workaround for https://github.com/vercel/next.js/issues/8592, mark when
|
||||||
|
* getInitialProps has run
|
||||||
|
*/
|
||||||
errorInitialProps.hasGetInitialPropsRun = true;
|
errorInitialProps.hasGetInitialPropsRun = true;
|
||||||
|
|
||||||
// Returning early because we don't want to log 404 errors to Sentry.
|
// Returning early because we don't want to log 404 errors to Sentry.
|
||||||
|
@ -40,32 +44,38 @@ MyError.getInitialProps = async (context: NextPageContext) => {
|
||||||
return errorInitialProps;
|
return errorInitialProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Running on the server, the response object (`res`) is available.
|
/*
|
||||||
//
|
* Running on the server, the response object (`res`) is available.
|
||||||
// Next.js will pass an err on the server if a page's data fetching methods
|
*
|
||||||
// threw or returned a Promise that rejected
|
* Next.js will pass an err on the server if a page's data fetching methods
|
||||||
//
|
* threw or returned a Promise that rejected
|
||||||
// Running on the client (browser), Next.js will provide an err if:
|
*
|
||||||
//
|
* Running on the client (browser), Next.js will provide an err if:
|
||||||
// - a page's `getInitialProps` threw or returned a Promise that rejected
|
*
|
||||||
// - an exception was thrown somewhere in the React lifecycle (render,
|
* - a page's `getInitialProps` threw or returned a Promise that rejected
|
||||||
// componentDidMount, etc) that was caught by Next.js's React Error
|
* - an exception was thrown somewhere in the React lifecycle (render,
|
||||||
// Boundary. Read more about what types of exceptions are caught by Error
|
* componentDidMount, etc) that was caught by Next.js's React Error
|
||||||
// Boundaries: https://reactjs.org/docs/error-boundaries.html
|
* Boundary. Read more about what types of exceptions are caught by Error
|
||||||
|
* Boundaries: https://reactjs.org/docs/error-boundaries.html
|
||||||
|
*/
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
Sentry.captureException(err);
|
Sentry.captureException(err);
|
||||||
|
|
||||||
// Flushing before returning is necessary if deploying to Vercel, see
|
/*
|
||||||
// https://vercel.com/docs/platform/limits#streaming-responses
|
* Flushing before returning is necessary if deploying to Vercel, see
|
||||||
|
* https://vercel.com/docs/platform/limits#streaming-responses
|
||||||
|
*/
|
||||||
await Sentry.flush(2000);
|
await Sentry.flush(2000);
|
||||||
|
|
||||||
return errorInitialProps;
|
return errorInitialProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this point is reached, getInitialProps was called without any
|
/*
|
||||||
// information about what the error might be. This is unexpected and may
|
* If this point is reached, getInitialProps was called without any
|
||||||
// indicate a bug introduced in Next.js, so record it in Sentry
|
* information about what the error might be. This is unexpected and may
|
||||||
|
* indicate a bug introduced in Next.js, so record it in Sentry
|
||||||
|
*/
|
||||||
Sentry.captureException(new Error(`_error.js getInitialProps missing data at path: ${asPath}`));
|
Sentry.captureException(new Error(`_error.js getInitialProps missing data at path: ${asPath}`));
|
||||||
await Sentry.flush(2000);
|
await Sentry.flush(2000);
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,7 @@ const handler: NextWebhookApiHandler<CustomerCreatedWebhookPayloadFragment> = as
|
||||||
|
|
||||||
if (klaviyoResponse.status !== 200) {
|
if (klaviyoResponse.status !== 200) {
|
||||||
const klaviyoMessage = ` Message: ${(await klaviyoResponse.json())?.message}.` || "";
|
const klaviyoMessage = ` Message: ${(await klaviyoResponse.json())?.message}.` || "";
|
||||||
|
|
||||||
console.debug("Klaviyo returned error: ", klaviyoMessage);
|
console.debug("Klaviyo returned error: ", klaviyoMessage);
|
||||||
|
|
||||||
return res.status(500).json({
|
return res.status(500).json({
|
||||||
|
|
|
@ -96,6 +96,7 @@ const handler: NextWebhookApiHandler<FulfillmentCreatedWebhookPayloadFragment> =
|
||||||
|
|
||||||
if (klaviyoResponse.status !== 200) {
|
if (klaviyoResponse.status !== 200) {
|
||||||
const klaviyoMessage = ` Message: ${(await klaviyoResponse.json())?.message}.` || "";
|
const klaviyoMessage = ` Message: ${(await klaviyoResponse.json())?.message}.` || "";
|
||||||
|
|
||||||
console.debug("Klaviyo returned error: ", klaviyoMessage);
|
console.debug("Klaviyo returned error: ", klaviyoMessage);
|
||||||
|
|
||||||
return res.status(500).json({
|
return res.status(500).json({
|
||||||
|
|
|
@ -67,6 +67,7 @@ const handler: NextWebhookApiHandler<OrderCreatedWebhookPayloadFragment> = async
|
||||||
|
|
||||||
if (klaviyoResponse.status !== 200) {
|
if (klaviyoResponse.status !== 200) {
|
||||||
const klaviyoMessage = ` Message: ${(await klaviyoResponse.json())?.message}.` || "";
|
const klaviyoMessage = ` Message: ${(await klaviyoResponse.json())?.message}.` || "";
|
||||||
|
|
||||||
console.debug("Klaviyo returned error: ", klaviyoMessage);
|
console.debug("Klaviyo returned error: ", klaviyoMessage);
|
||||||
return res.status(500).json({
|
return res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
|
|
|
@ -67,6 +67,7 @@ const handler: NextWebhookApiHandler<OrderFullyPaidWebhookPayloadFragment> = asy
|
||||||
|
|
||||||
if (klaviyoResponse.status !== 200) {
|
if (klaviyoResponse.status !== 200) {
|
||||||
const klaviyoMessage = ` Message: ${(await klaviyoResponse.json())?.message}.` || "";
|
const klaviyoMessage = ` Message: ${(await klaviyoResponse.json())?.message}.` || "";
|
||||||
|
|
||||||
console.debug("Klaviyo returned error: ", klaviyoMessage);
|
console.debug("Klaviyo returned error: ", klaviyoMessage);
|
||||||
|
|
||||||
return res.status(500).json({
|
return res.status(500).json({
|
||||||
|
|
|
@ -171,6 +171,7 @@ function Configuration() {
|
||||||
|
|
||||||
const onChange = (event: ChangeEvent) => {
|
const onChange = (event: ChangeEvent) => {
|
||||||
const { name, value } = event.target as HTMLInputElement;
|
const { name, value } = event.target as HTMLInputElement;
|
||||||
|
|
||||||
setConfiguration((prev) =>
|
setConfiguration((prev) =>
|
||||||
prev!.map((prevField) => (prevField.key === name ? { ...prevField, value } : prevField))
|
prev!.map((prevField) => (prevField.key === name ? { ...prevField, value } : prevField))
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
},
|
},
|
||||||
|
@ -55,9 +56,5 @@
|
||||||
"eslint-config-saleor": "workspace:*",
|
"eslint-config-saleor": "workspace:*",
|
||||||
"prettier": "^2.8.2",
|
"prettier": "^2.8.2",
|
||||||
"typescript": "4.9.4"
|
"typescript": "4.9.4"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ function NextApp({ Component, pageProps }: AppProps) {
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const jssStyles = document.querySelector("#jss-server-side");
|
const jssStyles = document.querySelector("#jss-server-side");
|
||||||
|
|
||||||
if (jssStyles) {
|
if (jssStyles) {
|
||||||
jssStyles?.parentElement?.removeChild(jssStyles);
|
jssStyles?.parentElement?.removeChild(jssStyles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
|
@ -69,9 +70,5 @@
|
||||||
"eslint-config-saleor": "workspace:*",
|
"eslint-config-saleor": "workspace:*",
|
||||||
"prettier": "^2.8.2",
|
"prettier": "^2.8.2",
|
||||||
"typescript": "4.9.4"
|
"typescript": "4.9.4"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,5 +86,6 @@ export const generateGoogleXmlFeed = ({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return builder.build(data);
|
return builder.build(data);
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,9 +81,11 @@ export async function mutateMetadata(client: Client, metadata: MetadataEntry[])
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createSettingsManager = (client: Client) => {
|
export const createSettingsManager = (client: Client) => {
|
||||||
// EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
/*
|
||||||
// We recommend it for production, because all values are encrypted.
|
* EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
||||||
// If your use case require plain text values, you can use MetadataManager.
|
* We recommend it for production, because all values are encrypted.
|
||||||
|
* If your use case require plain text values, you can use MetadataManager.
|
||||||
|
*/
|
||||||
return new EncryptedMetadataManager({
|
return new EncryptedMetadataManager({
|
||||||
// Secret key should be randomly created for production and set as environment variable
|
// Secret key should be randomly created for production and set as environment variable
|
||||||
encryptionKey: process.env.SECRET_KEY!,
|
encryptionKey: process.env.SECRET_KEY!,
|
||||||
|
|
|
@ -36,6 +36,7 @@ export const FeedPreviewCard = ({ channelSlug }: FeedPreviewCardProps) => {
|
||||||
const openUrlInNewTab = async (url: string) => {
|
const openUrlInNewTab = async (url: string) => {
|
||||||
await appBridge?.dispatch(actions.Redirect({ to: url, newContext: true }));
|
await appBridge?.dispatch(actions.Redirect({ to: url, newContext: true }));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper elevation={0} className={styles.instructionsContainer}>
|
<Paper elevation={0} className={styles.instructionsContainer}>
|
||||||
<Typography paragraph variant="h3">
|
<Typography paragraph variant="h3">
|
||||||
|
|
|
@ -65,6 +65,7 @@ export const SideMenu: React.FC<SideMenuProps> = ({
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const isNoItems = !items || !items.length;
|
const isNoItems = !items || !items.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={classes.menu}>
|
<Card className={classes.menu}>
|
||||||
<CardHeader title={title} action={headerToolbar} />
|
<CardHeader title={title} action={headerToolbar} />
|
||||||
|
|
|
@ -38,6 +38,7 @@ export const categoryMappingRouter = router({
|
||||||
.input(SetCategoryMappingInputSchema)
|
.input(SetCategoryMappingInputSchema)
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
|
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
|
||||||
|
|
||||||
logger.debug("categoriesRouter.setCategoryMapping called");
|
logger.debug("categoriesRouter.setCategoryMapping called");
|
||||||
const { error } = await ctx.apiClient
|
const { error } = await ctx.apiClient
|
||||||
.mutation(UpdateCategoryMappingDocument, {
|
.mutation(UpdateCategoryMappingDocument, {
|
||||||
|
|
|
@ -28,10 +28,12 @@ export const ConfigurationPageBaseLayout = ({ children }: Props) => {
|
||||||
|
|
||||||
const navigateToTab = (value: string) => {
|
const navigateToTab = (value: string) => {
|
||||||
const redirectionUrl = tabs.find((tab) => tab.key === value)?.url;
|
const redirectionUrl = tabs.find((tab) => tab.key === value)?.url;
|
||||||
|
|
||||||
if (redirectionUrl) {
|
if (redirectionUrl) {
|
||||||
router.push(redirectionUrl);
|
router.push(redirectionUrl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.appContainer}>
|
<div className={styles.appContainer}>
|
||||||
<PageTabs value={activePath} onChange={navigateToTab}>
|
<PageTabs value={activePath} onChange={navigateToTab}>
|
||||||
|
|
|
@ -63,6 +63,7 @@ const generateClassName = createGenerateClassName({
|
||||||
* Ensure instance is a singleton.
|
* Ensure instance is a singleton.
|
||||||
* TODO: This is React 18 issue, consider hiding this workaround inside app-sdk
|
* TODO: This is React 18 issue, consider hiding this workaround inside app-sdk
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const appBridgeInstance = typeof window !== "undefined" ? new AppBridge() : undefined;
|
export const appBridgeInstance = typeof window !== "undefined" ? new AppBridge() : undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,6 +79,7 @@ function NextApp({ Component, pageProps }: AppProps) {
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const jssStyles = document.querySelector("#jss-server-side");
|
const jssStyles = document.querySelector("#jss-server-side");
|
||||||
|
|
||||||
if (jssStyles) {
|
if (jssStyles) {
|
||||||
jssStyles?.parentElement?.removeChild(jssStyles);
|
jssStyles?.parentElement?.removeChild(jssStyles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
channel,
|
channel,
|
||||||
route: "api/feed/{url}/{channel}/google.xml",
|
route: "api/feed/{url}/{channel}/google.xml",
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.debug("Feed route visited");
|
logger.debug("Feed route visited");
|
||||||
|
|
||||||
if (!url.length) {
|
if (!url.length) {
|
||||||
|
@ -59,8 +60,10 @@ export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
|
|
||||||
let storefrontUrl: string;
|
let storefrontUrl: string;
|
||||||
let productStorefrontUrl: string;
|
let productStorefrontUrl: string;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const settings = await getGoogleFeedSettings({ authData, channel });
|
const settings = await getGoogleFeedSettings({ authData, channel });
|
||||||
|
|
||||||
storefrontUrl = settings.storefrontUrl;
|
storefrontUrl = settings.storefrontUrl;
|
||||||
productStorefrontUrl = settings.productStorefrontUrl;
|
productStorefrontUrl = settings.productStorefrontUrl;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -72,8 +75,10 @@ export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
|
|
||||||
let shopName: string;
|
let shopName: string;
|
||||||
let shopDescription: string | undefined;
|
let shopDescription: string | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const shopDetails = await fetchShopData({ client, channel });
|
const shopDetails = await fetchShopData({ client, channel });
|
||||||
|
|
||||||
shopName = shopDetails.shopName;
|
shopName = shopDetails.shopName;
|
||||||
shopDescription = shopDetails.shopDescription;
|
shopDescription = shopDetails.shopDescription;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// This file sets a custom webpack configuration to use your Next.js app
|
/*
|
||||||
// with Sentry.
|
* This file sets a custom webpack configuration to use your Next.js app
|
||||||
// https://nextjs.org/docs/api-reference/next.config.js/introduction
|
* with Sentry.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* https://nextjs.org/docs/api-reference/next.config.js/introduction
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
const { withSentryConfig } = require("@sentry/nextjs");
|
const { withSentryConfig } = require("@sentry/nextjs");
|
||||||
|
|
||||||
|
@ -23,12 +25,14 @@ const moduleExports = {
|
||||||
},
|
},
|
||||||
transpilePackages: ["@saleor/apps-shared"],
|
transpilePackages: ["@saleor/apps-shared"],
|
||||||
sentry: {
|
sentry: {
|
||||||
// Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
|
/*
|
||||||
// for client-side builds. (This will be the default starting in
|
* Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
|
||||||
// `@sentry/nextjs` version 8.0.0.) See
|
* for client-side builds. (This will be the default starting in
|
||||||
// https://webpack.js.org/configuration/devtool/ and
|
* `@sentry/nextjs` version 8.0.0.) See
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
|
* https://webpack.js.org/configuration/devtool/ and
|
||||||
// for more information.
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
|
||||||
|
* for more information.
|
||||||
|
*/
|
||||||
hideSourceMaps: true,
|
hideSourceMaps: true,
|
||||||
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
|
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
|
||||||
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
|
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
|
||||||
|
@ -36,17 +40,23 @@ const moduleExports = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const sentryWebpackPluginOptions = {
|
const sentryWebpackPluginOptions = {
|
||||||
// Additional config options for the Sentry Webpack plugin. Keep in mind that
|
/*
|
||||||
// the following options are set automatically, and overriding them is not
|
* Additional config options for the Sentry Webpack plugin. Keep in mind that
|
||||||
// recommended:
|
* the following options are set automatically, and overriding them is not
|
||||||
// release, url, org, project, authToken, configFile, stripPrefix,
|
* recommended:
|
||||||
// urlPrefix, include, ignore
|
* release, url, org, project, authToken, configFile, stripPrefix,
|
||||||
|
* urlPrefix, include, ignore
|
||||||
|
*/
|
||||||
|
|
||||||
silent: true, // Suppresses all logs
|
silent: true, // Suppresses all logs
|
||||||
// For all available options, see:
|
/*
|
||||||
// https://github.com/getsentry/sentry-webpack-plugin#options.
|
* For all available options, see:
|
||||||
|
* https://github.com/getsentry/sentry-webpack-plugin#options.
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure adding Sentry options is the last code to run before exporting, to
|
/*
|
||||||
// ensure that your source maps include changes from all other Webpack plugins
|
* Make sure adding Sentry options is the last code to run before exporting, to
|
||||||
|
* ensure that your source maps include changes from all other Webpack plugins
|
||||||
|
*/
|
||||||
module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);
|
module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen"
|
"generate": "graphql-codegen"
|
||||||
},
|
},
|
||||||
|
@ -58,9 +59,5 @@
|
||||||
"eslint-config-saleor": "workspace:*",
|
"eslint-config-saleor": "workspace:*",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"typescript": "4.8.4"
|
"typescript": "4.8.4"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the browser.
|
/*
|
||||||
// The config you add here will be used whenever a page is visited.
|
* This file configures the initialization of Sentry on the browser.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever a page is visited.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from '@sentry/nextjs';
|
import * as Sentry from '@sentry/nextjs';
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever middleware or an Edge route handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever middleware or an Edge route handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from '@sentry/nextjs';
|
import * as Sentry from '@sentry/nextjs';
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever the server handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever the server handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from '@sentry/nextjs';
|
import * as Sentry from '@sentry/nextjs';
|
||||||
|
|
||||||
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
|
const SENTRY_DSN = process.env.SENTRY_DSN
|
||||||
|
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,8 +49,10 @@ export const AlgoliaConfigurationCard = () => {
|
||||||
},
|
},
|
||||||
body: JSON.stringify(conf),
|
body: JSON.stringify(conf),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (resp.status >= 200 && resp.status < 300) {
|
if (resp.status >= 200 && resp.status < 300) {
|
||||||
const data = (await resp.json()) as { data?: AlgoliaConfigurationFields };
|
const data = (await resp.json()) as { data?: AlgoliaConfigurationFields };
|
||||||
|
|
||||||
return data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
throw new Error(`Server responded with status code ${resp.status}`);
|
throw new Error(`Server responded with status code ${resp.status}`);
|
||||||
|
|
|
@ -20,6 +20,7 @@ function Hit(props: { hit: any }) {
|
||||||
|
|
||||||
export function Hits() {
|
export function Hits() {
|
||||||
const { hits } = useHits();
|
const { hits } = useHits();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.hitsWrapper}>
|
<div className={styles.hitsWrapper}>
|
||||||
{hits.map((hit) => (
|
{hits.map((hit) => (
|
||||||
|
|
|
@ -10,6 +10,7 @@ export function SearchBox() {
|
||||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
refine(e.target.value);
|
refine(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.textFieldContainer}>
|
<div className={styles.textFieldContainer}>
|
||||||
<TextField
|
<TextField
|
||||||
|
|
|
@ -66,6 +66,7 @@ export const useQueryAllProducts = (paused: boolean) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const channels = await getChannels();
|
const channels = await getChannels();
|
||||||
// get all products for each channel
|
// get all products for each channel
|
||||||
|
|
||||||
await channels.data?.channels?.reduce(async (acc, channel) => {
|
await channels.data?.channels?.reduce(async (acc, channel) => {
|
||||||
await acc;
|
await acc;
|
||||||
await getProducts(channel.slug, "");
|
await getProducts(channel.slug, "");
|
||||||
|
|
|
@ -34,6 +34,7 @@ export class AlgoliaSearchProvider implements SearchProvider {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
Object.entries(groupedByIndex).map(([indexName, objects]) => {
|
Object.entries(groupedByIndex).map(([indexName, objects]) => {
|
||||||
const index = this.#algolia.initIndex(indexName);
|
const index = this.#algolia.initIndex(indexName);
|
||||||
|
|
||||||
return index.saveObjects(objects);
|
return index.saveObjects(objects);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -45,6 +46,7 @@ export class AlgoliaSearchProvider implements SearchProvider {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
Object.entries(groupedByIndex).map(([indexName, objects]) => {
|
Object.entries(groupedByIndex).map(([indexName, objects]) => {
|
||||||
const index = this.#algolia.initIndex(indexName);
|
const index = this.#algolia.initIndex(indexName);
|
||||||
|
|
||||||
return index.deleteObjects(objects.map((o) => o.objectID));
|
return index.deleteObjects(objects.map((o) => o.objectID));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -57,6 +59,7 @@ export class AlgoliaSearchProvider implements SearchProvider {
|
||||||
visibleInListings: true,
|
visibleInListings: true,
|
||||||
indexNamePrefix: this.#indexNamePrefix,
|
indexNamePrefix: this.#indexNamePrefix,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.saveGroupedByIndex(groupedByIndex);
|
await this.saveGroupedByIndex(groupedByIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +131,7 @@ export class AlgoliaSearchProvider implements SearchProvider {
|
||||||
visibleInListings: null,
|
visibleInListings: null,
|
||||||
indexNamePrefix: this.#indexNamePrefix,
|
indexNamePrefix: this.#indexNamePrefix,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (groupedByIndexToDelete) {
|
if (groupedByIndexToDelete) {
|
||||||
await this.deleteGroupedByIndex(groupedByIndexToDelete);
|
await this.deleteGroupedByIndex(groupedByIndexToDelete);
|
||||||
}
|
}
|
||||||
|
@ -157,6 +161,7 @@ const groupVariantByIndexName = (
|
||||||
variant: productVariant,
|
variant: productVariant,
|
||||||
channel: channelListing.channel.slug,
|
channel: channelListing.channel.slug,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
object,
|
object,
|
||||||
indexName: channelListingToAlgoliaIndexId(channelListing, indexNamePrefix),
|
indexName: channelListingToAlgoliaIndexId(channelListing, indexNamePrefix),
|
||||||
|
@ -190,5 +195,6 @@ const groupProductsByIndexName = (
|
||||||
acc[indexName].push(...objects);
|
acc[indexName].push(...objects);
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as GroupedByIndex);
|
}, {} as GroupedByIndex);
|
||||||
|
|
||||||
return groupedByIndex;
|
return groupedByIndex;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@ export function channelListingToAlgoliaIndexId(
|
||||||
channelListing.channel.currencyCode,
|
channelListing.channel.currencyCode,
|
||||||
"products",
|
"products",
|
||||||
];
|
];
|
||||||
|
|
||||||
return nameSegments.filter(isNotNil).join(".");
|
return nameSegments.filter(isNotNil).join(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +86,7 @@ export function productAndVariantToAlgolia({
|
||||||
const attributes = {
|
const attributes = {
|
||||||
...product.attributes.reduce((acc, attr, idx) => {
|
...product.attributes.reduce((acc, attr, idx) => {
|
||||||
const preparedAttr = mapSelectedAttributesToRecord(attr);
|
const preparedAttr = mapSelectedAttributesToRecord(attr);
|
||||||
|
|
||||||
if (!preparedAttr) {
|
if (!preparedAttr) {
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +97,7 @@ export function productAndVariantToAlgolia({
|
||||||
}, {}),
|
}, {}),
|
||||||
...variant.attributes.reduce((acc, attr, idx) => {
|
...variant.attributes.reduce((acc, attr, idx) => {
|
||||||
const preparedAttr = mapSelectedAttributesToRecord(attr);
|
const preparedAttr = mapSelectedAttributesToRecord(attr);
|
||||||
|
|
||||||
if (!preparedAttr) {
|
if (!preparedAttr) {
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +126,7 @@ export function productAndVariantToAlgolia({
|
||||||
collections: product.collections?.map((collection) => collection.name) || [],
|
collections: product.collections?.map((collection) => collection.name) || [],
|
||||||
metadata: formatMetadata(variant),
|
metadata: formatMetadata(variant),
|
||||||
};
|
};
|
||||||
|
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ export const getAlgoliaConfiguration = async ({ authData }: GetAlgoliaConfigurat
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const secretKey = await settings.get("secretKey", authData.domain);
|
const secretKey = await settings.get("secretKey", authData.domain);
|
||||||
|
|
||||||
if (!secretKey?.length) {
|
if (!secretKey?.length) {
|
||||||
return {
|
return {
|
||||||
errors: [
|
errors: [
|
||||||
|
@ -30,6 +31,7 @@ export const getAlgoliaConfiguration = async ({ authData }: GetAlgoliaConfigurat
|
||||||
}
|
}
|
||||||
|
|
||||||
const appId = await settings.get("appId", authData.domain);
|
const appId = await settings.get("appId", authData.domain);
|
||||||
|
|
||||||
if (!appId?.length) {
|
if (!appId?.length) {
|
||||||
return {
|
return {
|
||||||
errors: [
|
errors: [
|
||||||
|
@ -41,6 +43,7 @@ export const getAlgoliaConfiguration = async ({ authData }: GetAlgoliaConfigurat
|
||||||
}
|
}
|
||||||
|
|
||||||
const indexNamePrefix = (await settings.get("indexNamePrefix", authData.domain)) || "";
|
const indexNamePrefix = (await settings.get("indexNamePrefix", authData.domain)) || "";
|
||||||
|
|
||||||
debug("Configuration fetched");
|
debug("Configuration fetched");
|
||||||
return {
|
return {
|
||||||
settings: {
|
settings: {
|
||||||
|
|
|
@ -9,6 +9,7 @@ export const fetchConfiguration = async (saleorApiUrl: string, token: string) =>
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const data = (await res.json()) as { data?: AlgoliaConfigurationFields };
|
const data = (await res.json()) as { data?: AlgoliaConfigurationFields };
|
||||||
|
|
||||||
return data.data;
|
return data.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,12 @@ import {
|
||||||
} from "../../generated/graphql";
|
} from "../../generated/graphql";
|
||||||
import { settingsManagerSecretKey } from "../../saleor-app";
|
import { settingsManagerSecretKey } from "../../saleor-app";
|
||||||
|
|
||||||
// Function is using urql graphql client to fetch all available metadata.
|
/*
|
||||||
// Before returning query result, we are transforming response to list of objects with key and value fields
|
* Function is using urql graphql client to fetch all available metadata.
|
||||||
// which can be used by the manager.
|
* Before returning query result, we are transforming response to list of objects with key and value fields
|
||||||
// Result of this query is cached by the manager.
|
* which can be used by the manager.
|
||||||
|
* Result of this query is cached by the manager.
|
||||||
|
*/
|
||||||
export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]> {
|
export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]> {
|
||||||
const { error, data } = await client
|
const { error, data } = await client
|
||||||
.query<FetchAppDetailsQuery>(FetchAppDetailsDocument, {})
|
.query<FetchAppDetailsQuery>(FetchAppDetailsDocument, {})
|
||||||
|
@ -25,9 +27,11 @@ export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]>
|
||||||
return data?.app?.privateMetadata.map((md) => ({ key: md.key, value: md.value })) || [];
|
return data?.app?.privateMetadata.map((md) => ({ key: md.key, value: md.value })) || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutate function takes urql client and metadata entries, and construct mutation to the API.
|
/*
|
||||||
// Before data are send, additional query for required App ID is made.
|
* Mutate function takes urql client and metadata entries, and construct mutation to the API.
|
||||||
// The manager will use updated entries returned by this mutation to update it's cache.
|
* Before data are send, additional query for required App ID is made.
|
||||||
|
* The manager will use updated entries returned by this mutation to update it's cache.
|
||||||
|
*/
|
||||||
export async function mutateMetadata(client: Client, metadata: MetadataEntry[]) {
|
export async function mutateMetadata(client: Client, metadata: MetadataEntry[]) {
|
||||||
// to update the metadata, ID is required
|
// to update the metadata, ID is required
|
||||||
const { error: idQueryError, data: idQueryData } = await client
|
const { error: idQueryError, data: idQueryData } = await client
|
||||||
|
@ -69,9 +73,11 @@ export async function mutateMetadata(client: Client, metadata: MetadataEntry[])
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createSettingsManager = (client: Client) => {
|
export const createSettingsManager = (client: Client) => {
|
||||||
// EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
/*
|
||||||
// We recommend it for production, because all values are encrypted.
|
* EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
||||||
// If your use case require plain text values, you can use MetadataManager.
|
* We recommend it for production, because all values are encrypted.
|
||||||
|
* If your use case require plain text values, you can use MetadataManager.
|
||||||
|
*/
|
||||||
return new EncryptedMetadataManager({
|
return new EncryptedMetadataManager({
|
||||||
// Secret key should be randomly created for production and set as environment variable
|
// Secret key should be randomly created for production and set as environment variable
|
||||||
encryptionKey: settingsManagerSecretKey,
|
encryptionKey: settingsManagerSecretKey,
|
||||||
|
|
|
@ -35,6 +35,7 @@ const queryClient = new QueryClient({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
type PalettesOverride = Record<"light" | "dark", SaleorThemeColors>;
|
type PalettesOverride = Record<"light" | "dark", SaleorThemeColors>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,6 +74,7 @@ function NextApp({ Component, pageProps }: AppProps) {
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const jssStyles = document.querySelector("#jss-server-side");
|
const jssStyles = document.querySelector("#jss-server-side");
|
||||||
|
|
||||||
if (jssStyles) {
|
if (jssStyles) {
|
||||||
jssStyles?.parentElement?.removeChild(jssStyles);
|
jssStyles?.parentElement?.removeChild(jssStyles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,16 +20,20 @@ import * as Sentry from '@sentry/nextjs';
|
||||||
import NextErrorComponent from 'next/error';
|
import NextErrorComponent from 'next/error';
|
||||||
|
|
||||||
const CustomErrorComponent = props => {
|
const CustomErrorComponent = props => {
|
||||||
// If you're using a Nextjs version prior to 12.2.1, uncomment this to
|
/*
|
||||||
// compensate for https://github.com/vercel/next.js/issues/8592
|
* If you're using a Nextjs version prior to 12.2.1, uncomment this to
|
||||||
// Sentry.captureUnderscoreErrorException(props);
|
* compensate for https://github.com/vercel/next.js/issues/8592
|
||||||
|
* Sentry.captureUnderscoreErrorException(props);
|
||||||
|
*/
|
||||||
|
|
||||||
return <NextErrorComponent statusCode={props.statusCode} />;
|
return <NextErrorComponent statusCode={props.statusCode} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
CustomErrorComponent.getInitialProps = async contextData => {
|
CustomErrorComponent.getInitialProps = async contextData => {
|
||||||
// In case this is running in a serverless function, await this in order to give Sentry
|
/*
|
||||||
// time to send the error before the lambda exits
|
* In case this is running in a serverless function, await this in order to give Sentry
|
||||||
|
* time to send the error before the lambda exits
|
||||||
|
*/
|
||||||
await Sentry.captureUnderscoreErrorException(contextData);
|
await Sentry.captureUnderscoreErrorException(contextData);
|
||||||
|
|
||||||
// This will contain the status code of the response
|
// This will contain the status code of the response
|
||||||
|
|
|
@ -58,6 +58,7 @@ export const handler = async (
|
||||||
const { appId, searchKey, secretKey, indexNamePrefix } = JSON.parse(
|
const { appId, searchKey, secretKey, indexNamePrefix } = JSON.parse(
|
||||||
req.body
|
req.body
|
||||||
) as AlgoliaConfigurationFields;
|
) as AlgoliaConfigurationFields;
|
||||||
|
|
||||||
await settings.set([
|
await settings.set([
|
||||||
{ key: "secretKey", value: secretKey || "", domain },
|
{ key: "secretKey", value: secretKey || "", domain },
|
||||||
{ key: "searchKey", value: searchKey || "", domain },
|
{ key: "searchKey", value: searchKey || "", domain },
|
||||||
|
|
|
@ -22,6 +22,7 @@ export const handler: NextWebhookApiHandler<ProductCreated> = async (req, res, c
|
||||||
const debug = createDebug(`Webhook handler - ${webhookProductCreated.event}`);
|
const debug = createDebug(`Webhook handler - ${webhookProductCreated.event}`);
|
||||||
|
|
||||||
const { event, authData } = context;
|
const { event, authData } = context;
|
||||||
|
|
||||||
debug(
|
debug(
|
||||||
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
||||||
);
|
);
|
||||||
|
@ -43,6 +44,7 @@ export const handler: NextWebhookApiHandler<ProductCreated> = async (req, res, c
|
||||||
});
|
});
|
||||||
|
|
||||||
const { product } = context.payload;
|
const { product } = context.payload;
|
||||||
|
|
||||||
if (product) {
|
if (product) {
|
||||||
await searchProvider.createProduct(product);
|
await searchProvider.createProduct(product);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ export const handler: NextWebhookApiHandler<ProductDeleted> = async (req, res, c
|
||||||
const debug = createDebug(`Webhook handler - ${webhookProductDeleted.event}`);
|
const debug = createDebug(`Webhook handler - ${webhookProductDeleted.event}`);
|
||||||
|
|
||||||
const { event, authData } = context;
|
const { event, authData } = context;
|
||||||
|
|
||||||
debug(
|
debug(
|
||||||
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
||||||
);
|
);
|
||||||
|
@ -43,6 +44,7 @@ export const handler: NextWebhookApiHandler<ProductDeleted> = async (req, res, c
|
||||||
});
|
});
|
||||||
|
|
||||||
const { product } = context.payload;
|
const { product } = context.payload;
|
||||||
|
|
||||||
if (product) {
|
if (product) {
|
||||||
await searchProvider.deleteProduct(product);
|
await searchProvider.deleteProduct(product);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ export const handler: NextWebhookApiHandler<ProductUpdated> = async (req, res, c
|
||||||
const debug = createDebug(`Webhook handler - ${webhookProductUpdated.event}`);
|
const debug = createDebug(`Webhook handler - ${webhookProductUpdated.event}`);
|
||||||
|
|
||||||
const { event, authData } = context;
|
const { event, authData } = context;
|
||||||
|
|
||||||
debug(
|
debug(
|
||||||
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
||||||
);
|
);
|
||||||
|
@ -43,6 +44,7 @@ export const handler: NextWebhookApiHandler<ProductUpdated> = async (req, res, c
|
||||||
});
|
});
|
||||||
|
|
||||||
const { product } = context.payload;
|
const { product } = context.payload;
|
||||||
|
|
||||||
if (product) {
|
if (product) {
|
||||||
await searchProvider.updateProduct(product);
|
await searchProvider.updateProduct(product);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ export const handler: NextWebhookApiHandler<ProductVariantCreated> = async (req,
|
||||||
const debug = createDebug(`Webhook handler - ${webhookProductVariantCreated.event}`);
|
const debug = createDebug(`Webhook handler - ${webhookProductVariantCreated.event}`);
|
||||||
|
|
||||||
const { event, authData } = context;
|
const { event, authData } = context;
|
||||||
|
|
||||||
debug(
|
debug(
|
||||||
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
||||||
);
|
);
|
||||||
|
@ -46,6 +47,7 @@ export const handler: NextWebhookApiHandler<ProductVariantCreated> = async (req,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { productVariant } = context.payload;
|
const { productVariant } = context.payload;
|
||||||
|
|
||||||
if (productVariant) {
|
if (productVariant) {
|
||||||
await searchProvider.createProductVariant(productVariant);
|
await searchProvider.createProductVariant(productVariant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ export const handler: NextWebhookApiHandler<ProductVariantDeleted> = async (req,
|
||||||
const debug = createDebug(`Webhook handler - ${webhookProductVariantDeleted.event}`);
|
const debug = createDebug(`Webhook handler - ${webhookProductVariantDeleted.event}`);
|
||||||
|
|
||||||
const { event, authData } = context;
|
const { event, authData } = context;
|
||||||
|
|
||||||
debug(
|
debug(
|
||||||
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
||||||
);
|
);
|
||||||
|
@ -46,6 +47,7 @@ export const handler: NextWebhookApiHandler<ProductVariantDeleted> = async (req,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { productVariant } = context.payload;
|
const { productVariant } = context.payload;
|
||||||
|
|
||||||
if (productVariant) {
|
if (productVariant) {
|
||||||
await searchProvider.deleteProductVariant(productVariant);
|
await searchProvider.deleteProductVariant(productVariant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ export const handler: NextWebhookApiHandler<ProductVariantUpdated> = async (req,
|
||||||
const debug = createDebug(`Webhook handler - ${webhookProductVariantUpdated.event}`);
|
const debug = createDebug(`Webhook handler - ${webhookProductVariantUpdated.event}`);
|
||||||
|
|
||||||
const { event, authData } = context;
|
const { event, authData } = context;
|
||||||
|
|
||||||
debug(
|
debug(
|
||||||
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
`New event ${event} (${context.payload?.__typename}) from the ${authData.domain} domain has been received!`
|
||||||
);
|
);
|
||||||
|
@ -46,6 +47,7 @@ export const handler: NextWebhookApiHandler<ProductVariantUpdated> = async (req,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { productVariant } = context.payload;
|
const { productVariant } = context.payload;
|
||||||
|
|
||||||
if (productVariant) {
|
if (productVariant) {
|
||||||
await searchProvider.updateProductVariant(productVariant);
|
await searchProvider.updateProductVariant(productVariant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
"ALLOWED_DOMAIN_PATTERN",
|
"ALLOWED_DOMAIN_PATTERN",
|
||||||
"REST_APL_ENDPOINT",
|
"REST_APL_ENDPOINT",
|
||||||
"REST_APL_TOKEN",
|
"REST_APL_TOKEN",
|
||||||
|
"SENTRY_AUTH_TOKEN",
|
||||||
|
"SENTRY_PROJECT",
|
||||||
|
"SENTRY_DSN",
|
||||||
|
"SENTRY_ORG",
|
||||||
"NEXT_PUBLIC_VERCEL_ENV"
|
"NEXT_PUBLIC_VERCEL_ENV"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// This file sets a custom webpack configuration to use your Next.js app
|
/*
|
||||||
// with Sentry.
|
* This file sets a custom webpack configuration to use your Next.js app
|
||||||
// https://nextjs.org/docs/api-reference/next.config.js/introduction
|
* with Sentry.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* https://nextjs.org/docs/api-reference/next.config.js/introduction
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
const { withSentryConfig } = require("@sentry/nextjs");
|
const { withSentryConfig } = require("@sentry/nextjs");
|
||||||
|
|
||||||
|
@ -18,28 +20,36 @@ const moduleExports = {
|
||||||
sentry: {
|
sentry: {
|
||||||
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
|
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
|
||||||
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
|
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
|
||||||
// Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
|
/*
|
||||||
// for client-side builds. (This will be the default starting in
|
* Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
|
||||||
// `@sentry/nextjs` version 8.0.0.) See
|
* for client-side builds. (This will be the default starting in
|
||||||
// https://webpack.js.org/configuration/devtool/ and
|
* `@sentry/nextjs` version 8.0.0.) See
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
|
* https://webpack.js.org/configuration/devtool/ and
|
||||||
// for more information.
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
|
||||||
|
* for more information.
|
||||||
|
*/
|
||||||
hideSourceMaps: true,
|
hideSourceMaps: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const sentryWebpackPluginOptions = {
|
const sentryWebpackPluginOptions = {
|
||||||
// Additional config options for the Sentry Webpack plugin. Keep in mind that
|
/*
|
||||||
// the following options are set automatically, and overriding them is not
|
* Additional config options for the Sentry Webpack plugin. Keep in mind that
|
||||||
// recommended:
|
* the following options are set automatically, and overriding them is not
|
||||||
// release, url, org, project, authToken, configFile, stripPrefix,
|
* recommended:
|
||||||
// urlPrefix, include, ignore
|
* release, url, org, project, authToken, configFile, stripPrefix,
|
||||||
|
* urlPrefix, include, ignore
|
||||||
|
*/
|
||||||
|
|
||||||
silent: true, // Suppresses all logs
|
silent: true, // Suppresses all logs
|
||||||
// For all available options, see:
|
/*
|
||||||
// https://github.com/getsentry/sentry-webpack-plugin#options.
|
* For all available options, see:
|
||||||
|
* https://github.com/getsentry/sentry-webpack-plugin#options.
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make sure adding Sentry options is the last code to run before exporting, to
|
/*
|
||||||
// ensure that your source maps include changes from all other Webpack plugins
|
* Make sure adding Sentry options is the last code to run before exporting, to
|
||||||
|
* ensure that your source maps include changes from all other Webpack plugins
|
||||||
|
*/
|
||||||
module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);
|
module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "pnpm generate && prettier --loglevel warn --write . && eslint --fix .",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen"
|
"generate": "graphql-codegen"
|
||||||
},
|
},
|
||||||
|
@ -54,9 +55,5 @@
|
||||||
"postcss": "^8.4.14",
|
"postcss": "^8.4.14",
|
||||||
"pretty-quick": "^3.1.3",
|
"pretty-quick": "^3.1.3",
|
||||||
"typescript": "4.8.3"
|
"typescript": "4.8.3"
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,ts,tsx}": "eslint --cache --fix",
|
|
||||||
"*.{js,ts,tsx,css,md,json}": "prettier --write"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// This file configures the initialization of Sentry on the browser.
|
/*
|
||||||
// The config you add here will be used whenever a page is visited.
|
* This file configures the initialization of Sentry on the browser.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever a page is visited.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
|
@ -10,8 +12,10 @@ Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever middleware or an Edge route handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever middleware or an Edge route handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
|
@ -10,8 +12,10 @@ Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// This file configures the initialization of Sentry on the server.
|
/*
|
||||||
// The config you add here will be used whenever the server handles a request.
|
* This file configures the initialization of Sentry on the server.
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
* The config you add here will be used whenever the server handles a request.
|
||||||
|
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
|
||||||
|
@ -10,8 +12,10 @@ Sentry.init({
|
||||||
dsn: SENTRY_DSN,
|
dsn: SENTRY_DSN,
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
// Adjust this value in production, or use tracesSampler for greater control
|
||||||
tracesSampleRate: 1.0,
|
tracesSampleRate: 1.0,
|
||||||
// ...
|
/*
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
* ...
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
* Note: if you want to override the automatic release value, do not set a
|
||||||
// that it will also get attached to your source maps
|
* `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||||
|
* that it will also get attached to your source maps
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,10 +12,12 @@ function _ThemeSynchronizer() {
|
||||||
const { appBridgeState, appBridge } = useAppBridge();
|
const { appBridgeState, appBridge } = useAppBridge();
|
||||||
const { setTheme, themeType } = useTheme();
|
const { setTheme, themeType } = useTheme();
|
||||||
|
|
||||||
// todo - replace this hook to appBridge.subscribe and react only only on initial theme event
|
/*
|
||||||
// useEffect(() =>{
|
* todo - replace this hook to appBridge.subscribe and react only only on initial theme event
|
||||||
// appBridge?.subscribe('theme',console.log)
|
* useEffect(() =>{
|
||||||
// },[appBridge])
|
* appBridge?.subscribe('theme',console.log)
|
||||||
|
* },[appBridge])
|
||||||
|
*/
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!setTheme || !appBridgeState?.theme) {
|
if (!setTheme || !appBridgeState?.theme) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ export const useAppApi = <D>({ url, options, skip }: UseFetchProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
|
|
||||||
setData(json);
|
setData(json);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(e as unknown);
|
setError(e as unknown);
|
||||||
|
|
|
@ -8,10 +8,12 @@ import {
|
||||||
} from "../../generated/graphql";
|
} from "../../generated/graphql";
|
||||||
import { settingsManagerSecretKey } from "./saleor-app";
|
import { settingsManagerSecretKey } from "./saleor-app";
|
||||||
|
|
||||||
// Function is using urql graphql client to fetch all available metadata.
|
/*
|
||||||
// Before returning query result, we are transforming response to list of objects with key and value fields
|
* Function is using urql graphql client to fetch all available metadata.
|
||||||
// which can be used by the manager.
|
* Before returning query result, we are transforming response to list of objects with key and value fields
|
||||||
// Result of this query is cached by the manager.
|
* which can be used by the manager.
|
||||||
|
* Result of this query is cached by the manager.
|
||||||
|
*/
|
||||||
export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]> {
|
export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]> {
|
||||||
const { error, data } = await client
|
const { error, data } = await client
|
||||||
.query<FetchAppDetailsQuery>(FetchAppDetailsDocument, {})
|
.query<FetchAppDetailsQuery>(FetchAppDetailsDocument, {})
|
||||||
|
@ -25,9 +27,11 @@ export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]>
|
||||||
return data?.app?.privateMetadata.map((md) => ({ key: md.key, value: md.value })) || [];
|
return data?.app?.privateMetadata.map((md) => ({ key: md.key, value: md.value })) || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutate function takes urql client and metadata entries, and construct mutation to the API.
|
/*
|
||||||
// Before data are send, additional query for required App ID is made.
|
* Mutate function takes urql client and metadata entries, and construct mutation to the API.
|
||||||
// The manager will use updated entries returned by this mutation to update it's cache.
|
* Before data are send, additional query for required App ID is made.
|
||||||
|
* The manager will use updated entries returned by this mutation to update it's cache.
|
||||||
|
*/
|
||||||
export async function mutateMetadata(client: Client, appId: string, metadata: MetadataEntry[]) {
|
export async function mutateMetadata(client: Client, appId: string, metadata: MetadataEntry[]) {
|
||||||
const { error: mutationError, data: mutationData } = await client
|
const { error: mutationError, data: mutationData } = await client
|
||||||
.mutation(UpdateAppMetadataDocument, {
|
.mutation(UpdateAppMetadataDocument, {
|
||||||
|
@ -50,9 +54,11 @@ export async function mutateMetadata(client: Client, appId: string, metadata: Me
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createSettingsManager = (client: Client, appId: string) =>
|
export const createSettingsManager = (client: Client, appId: string) =>
|
||||||
// EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
/*
|
||||||
// We recommend it for production, because all values are encrypted.
|
* EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
|
||||||
// If your use case require plain text values, you can use MetadataManager.
|
* We recommend it for production, because all values are encrypted.
|
||||||
|
* If your use case require plain text values, you can use MetadataManager.
|
||||||
|
*/
|
||||||
new EncryptedMetadataManager({
|
new EncryptedMetadataManager({
|
||||||
// Secret key should be randomly created for production and set as environment variable
|
// Secret key should be randomly created for production and set as environment variable
|
||||||
encryptionKey: settingsManagerSecretKey,
|
encryptionKey: settingsManagerSecretKey,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { SaleorApp } from "@saleor/app-sdk/saleor-app";
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let apl: APL;
|
let apl: APL;
|
||||||
|
|
||||||
switch (process.env.APL) {
|
switch (process.env.APL) {
|
||||||
case "upstash":
|
case "upstash":
|
||||||
// Require `UPSTASH_URL` and `UPSTASH_TOKEN` environment variables
|
// Require `UPSTASH_URL` and `UPSTASH_TOKEN` environment variables
|
||||||
|
@ -30,12 +31,14 @@ switch (process.env.APL) {
|
||||||
apl = new FileAPL();
|
apl = new FileAPL();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Investigate why no-ssr-wrapper does not prevent this code from execution during the build time
|
/*
|
||||||
// if (!process.env.SECRET_KEY && process.env.NODE_ENV === "production") {
|
* TODO: Investigate why no-ssr-wrapper does not prevent this code from execution during the build time
|
||||||
// throw new Error(
|
* if (!process.env.SECRET_KEY && process.env.NODE_ENV === "production") {
|
||||||
// "For production deployment SECRET_KEY is mandatory to use EncryptedSettingsManager."
|
* throw new Error(
|
||||||
// );
|
* "For production deployment SECRET_KEY is mandatory to use EncryptedSettingsManager."
|
||||||
// }
|
* );
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
// Use placeholder value for the development
|
// Use placeholder value for the development
|
||||||
export const settingsManagerSecretKey = process.env.SECRET_KEY || "CHANGE_ME";
|
export const settingsManagerSecretKey = process.env.SECRET_KEY || "CHANGE_ME";
|
||||||
|
|
|
@ -73,6 +73,7 @@ function SaleorApp({ Component, pageProps }: AppLayoutProps) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const jssStyles = document.querySelector("#jss-server-side");
|
const jssStyles = document.querySelector("#jss-server-side");
|
||||||
|
|
||||||
if (jssStyles) {
|
if (jssStyles) {
|
||||||
jssStyles?.parentElement?.removeChild(jssStyles);
|
jssStyles?.parentElement?.removeChild(jssStyles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,16 +20,20 @@ import * as Sentry from "@sentry/nextjs";
|
||||||
import NextErrorComponent from "next/error";
|
import NextErrorComponent from "next/error";
|
||||||
|
|
||||||
const CustomErrorComponent = (props) => {
|
const CustomErrorComponent = (props) => {
|
||||||
// If you're using a Nextjs version prior to 12.2.1, uncomment this to
|
/*
|
||||||
// compensate for https://github.com/vercel/next.js/issues/8592
|
* If you're using a Nextjs version prior to 12.2.1, uncomment this to
|
||||||
// Sentry.captureUnderscoreErrorException(props);
|
* compensate for https://github.com/vercel/next.js/issues/8592
|
||||||
|
* Sentry.captureUnderscoreErrorException(props);
|
||||||
|
*/
|
||||||
|
|
||||||
return <NextErrorComponent statusCode={props.statusCode} />;
|
return <NextErrorComponent statusCode={props.statusCode} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
CustomErrorComponent.getInitialProps = async (contextData) => {
|
CustomErrorComponent.getInitialProps = async (contextData) => {
|
||||||
// In case this is running in a serverless function, await this in order to give Sentry
|
/*
|
||||||
// time to send the error before the lambda exits
|
* In case this is running in a serverless function, await this in order to give Sentry
|
||||||
|
* time to send the error before the lambda exits
|
||||||
|
*/
|
||||||
await Sentry.captureUnderscoreErrorException(contextData);
|
await Sentry.captureUnderscoreErrorException(contextData);
|
||||||
|
|
||||||
// This will contain the status code of the response
|
// This will contain the status code of the response
|
||||||
|
|
|
@ -15,10 +15,12 @@ interface AppErrorProps extends ErrorProps {
|
||||||
|
|
||||||
function MyError({ statusCode, hasGetInitialPropsRun, err }: ErrorPageProps) {
|
function MyError({ statusCode, hasGetInitialPropsRun, err }: ErrorPageProps) {
|
||||||
if (!hasGetInitialPropsRun && err) {
|
if (!hasGetInitialPropsRun && err) {
|
||||||
// getInitialProps is not called when an exception is thrown
|
/*
|
||||||
// at the top level of a module while it is being loaded.
|
* getInitialProps is not called when an exception is thrown
|
||||||
// As a workaround, we pass err via _app.js so it can be captured
|
* at the top level of a module while it is being loaded.
|
||||||
// Read more: https://github.com/vercel/next.js/issues/8592.
|
* As a workaround, we pass err via _app.js so it can be captured
|
||||||
|
* Read more: https://github.com/vercel/next.js/issues/8592.
|
||||||
|
*/
|
||||||
Sentry.captureException(err);
|
Sentry.captureException(err);
|
||||||
// Flushing is not required in this case as it only happens on the client
|
// Flushing is not required in this case as it only happens on the client
|
||||||
}
|
}
|
||||||
|
@ -31,8 +33,10 @@ MyError.getInitialProps = async (context: NextPageContext) => {
|
||||||
|
|
||||||
const { res, err, asPath } = context;
|
const { res, err, asPath } = context;
|
||||||
|
|
||||||
// Workaround for https://github.com/vercel/next.js/issues/8592, mark when
|
/*
|
||||||
// getInitialProps has run
|
* Workaround for https://github.com/vercel/next.js/issues/8592, mark when
|
||||||
|
* getInitialProps has run
|
||||||
|
*/
|
||||||
errorInitialProps.hasGetInitialPropsRun = true;
|
errorInitialProps.hasGetInitialPropsRun = true;
|
||||||
|
|
||||||
// Returning early because we don't want to log 404 errors to Sentry.
|
// Returning early because we don't want to log 404 errors to Sentry.
|
||||||
|
@ -40,32 +44,38 @@ MyError.getInitialProps = async (context: NextPageContext) => {
|
||||||
return errorInitialProps;
|
return errorInitialProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Running on the server, the response object (`res`) is available.
|
/*
|
||||||
//
|
* Running on the server, the response object (`res`) is available.
|
||||||
// Next.js will pass an err on the server if a page's data fetching methods
|
*
|
||||||
// threw or returned a Promise that rejected
|
* Next.js will pass an err on the server if a page's data fetching methods
|
||||||
//
|
* threw or returned a Promise that rejected
|
||||||
// Running on the client (browser), Next.js will provide an err if:
|
*
|
||||||
//
|
* Running on the client (browser), Next.js will provide an err if:
|
||||||
// - a page's `getInitialProps` threw or returned a Promise that rejected
|
*
|
||||||
// - an exception was thrown somewhere in the React lifecycle (render,
|
* - a page's `getInitialProps` threw or returned a Promise that rejected
|
||||||
// componentDidMount, etc) that was caught by Next.js's React Error
|
* - an exception was thrown somewhere in the React lifecycle (render,
|
||||||
// Boundary. Read more about what types of exceptions are caught by Error
|
* componentDidMount, etc) that was caught by Next.js's React Error
|
||||||
// Boundaries: https://reactjs.org/docs/error-boundaries.html
|
* Boundary. Read more about what types of exceptions are caught by Error
|
||||||
|
* Boundaries: https://reactjs.org/docs/error-boundaries.html
|
||||||
|
*/
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
Sentry.captureException(err);
|
Sentry.captureException(err);
|
||||||
|
|
||||||
// Flushing before returning is necessary if deploying to Vercel, see
|
/*
|
||||||
// https://vercel.com/docs/platform/limits#streaming-responses
|
* Flushing before returning is necessary if deploying to Vercel, see
|
||||||
|
* https://vercel.com/docs/platform/limits#streaming-responses
|
||||||
|
*/
|
||||||
await Sentry.flush(2000);
|
await Sentry.flush(2000);
|
||||||
|
|
||||||
return errorInitialProps;
|
return errorInitialProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this point is reached, getInitialProps was called without any
|
/*
|
||||||
// information about what the error might be. This is unexpected and may
|
* If this point is reached, getInitialProps was called without any
|
||||||
// indicate a bug introduced in Next.js, so record it in Sentry
|
* information about what the error might be. This is unexpected and may
|
||||||
|
* indicate a bug introduced in Next.js, so record it in Sentry
|
||||||
|
*/
|
||||||
Sentry.captureException(new Error(`_error.js getInitialProps missing data at path: ${asPath}`));
|
Sentry.captureException(new Error(`_error.js getInitialProps missing data at path: ${asPath}`));
|
||||||
await Sentry.flush(2000);
|
await Sentry.flush(2000);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ export const handler = async (
|
||||||
case "POST": {
|
case "POST": {
|
||||||
const reqBody = req.body as PostRequestBody;
|
const reqBody = req.body as PostRequestBody;
|
||||||
const newWebhookUrl = (await reqBody.data?.find((entry) => entry.key === WEBHOOK_URL))?.value;
|
const newWebhookUrl = (await reqBody.data?.find((entry) => entry.key === WEBHOOK_URL))?.value;
|
||||||
|
|
||||||
if (!newWebhookUrl) {
|
if (!newWebhookUrl) {
|
||||||
console.error("New value for the webhook URL has not been found");
|
console.error("New value for the webhook URL has not been found");
|
||||||
res.status(400).json({
|
res.status(400).json({
|
||||||
|
|
|
@ -8,6 +8,7 @@ const handler = createAppRegisterHandler({
|
||||||
(url) => {
|
(url) => {
|
||||||
if (allowedUrlsPattern) {
|
if (allowedUrlsPattern) {
|
||||||
const regex = new RegExp(allowedUrlsPattern);
|
const regex = new RegExp(allowedUrlsPattern);
|
||||||
|
|
||||||
if (regex.test(url)) {
|
if (regex.test(url)) {
|
||||||
console.debug(`Registration from the URL ${url} has been accepted`);
|
console.debug(`Registration from the URL ${url} has been accepted`);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -107,6 +107,7 @@ const handler: NextWebhookApiHandler<OrderCreatedWebhookPayloadFragment> = async
|
||||||
|
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
const errorMessage = await response.text();
|
const errorMessage = await response.text();
|
||||||
|
|
||||||
console.error(`Slack API responded with code ${response.status}: ${errorMessage}`);
|
console.error(`Slack API responded with code ${response.status}: ${errorMessage}`);
|
||||||
|
|
||||||
return res.status(500).send({
|
return res.status(500).send({
|
||||||
|
|
|
@ -79,6 +79,7 @@ function Configuration() {
|
||||||
|
|
||||||
const onChange = (event: ChangeEvent) => {
|
const onChange = (event: ChangeEvent) => {
|
||||||
const { name, value } = event.target as HTMLInputElement;
|
const { name, value } = event.target as HTMLInputElement;
|
||||||
|
|
||||||
setConfiguration((prev) =>
|
setConfiguration((prev) =>
|
||||||
prev!.map((prevField) => (prevField.key === name ? { ...prevField, value } : prevField))
|
prev!.map((prevField) => (prevField.key === name ? { ...prevField, value } : prevField))
|
||||||
);
|
);
|
||||||
|
@ -129,6 +130,7 @@ function Instructions() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const slackUrl = new URL("https://api.slack.com/apps");
|
const slackUrl = new URL("https://api.slack.com/apps");
|
||||||
|
|
||||||
slackUrl.searchParams.append("new_app", "1");
|
slackUrl.searchParams.append("new_app", "1");
|
||||||
slackUrl.searchParams.append("manifest_json", JSON.stringify(data));
|
slackUrl.searchParams.append("manifest_json", JSON.stringify(data));
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"build": "pnpm generate && next build",
|
"build": "pnpm generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"lint:fix": "eslint --fix .",
|
||||||
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
"fetch-schema": "curl https://raw.githubusercontent.com/saleor/saleor/${npm_package_saleor_schemaVersion}/saleor/graphql/schema.graphql > graphql/schema.graphql",
|
||||||
"generate": "graphql-codegen",
|
"generate": "graphql-codegen",
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
|
|
|
@ -20,4 +20,5 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
ignorePatterns: ["next-env.d.ts"],
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,5 +20,8 @@
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint:fix": "eslint --fix ."
|
||||||
|
},
|
||||||
"main": "index.ts"
|
"main": "index.ts"
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
},
|
},
|
||||||
"generate": {
|
"generate": {
|
||||||
"outputs": ["generated/"]
|
"outputs": ["generated/"]
|
||||||
}
|
},
|
||||||
|
"lint:fix": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue