Extract logger (#439)

* Extract logger

* Replace logger with shared one

* Replace CRM logger with shared one

* Replace E&M logger with shared one

* Replace invoices logger with shared one

* Replace Products Feed logger with shared one

* Replace Search logger with shared one

* Replace Taxes logger with shared one

* Uninstall pino from apps direct dependency

* Update docs

* Update changeset

* Bumped Klaviyo typescript version to hopefully unblock the build

* Change packageManager field to pnpm 8.2.0

* removed package manager field from klaviyo package.json
This commit is contained in:
Lukasz Ostrowski 2023-05-05 08:15:47 +02:00 committed by GitHub
parent b56894fa14
commit 830cfe92ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
103 changed files with 415 additions and 362 deletions

View file

@ -0,0 +1,15 @@
---
"saleor-app-emails-and-messages": minor
"saleor-app-products-feed": minor
"saleor-app-invoices": minor
"saleor-app-search": minor
"saleor-app-taxes": minor
"saleor-app-cms": minor
"saleor-app-crm": minor
"saleor-app-data-importer": minor
"saleor-app-klaviyo": minor
"saleor-app-monitoring": minor
"saleor-app-slack": minor
---
Changed APP_DEBUG env to APP_LOG_LEVEL

View file

@ -0,0 +1,11 @@
---
"saleor-app-emails-and-messages": patch
"saleor-app-products-feed": patch
"saleor-app-invoices": patch
"saleor-app-search": patch
"saleor-app-taxes": patch
"saleor-app-cms": patch
"saleor-app-crm": patch
---
Replaced internal logger implementation with shared logger

View file

@ -0,0 +1,5 @@
---
"@saleor/apps-shared": minor
---
Add Pino logger and renamed required env to be APP_LOG_LEVEL

View file

@ -0,0 +1,5 @@
---
"saleor-app-klaviyo": patch
---
Bumped Typescript version to 5.0.4

View file

@ -38,14 +38,17 @@ This repository serves as a starting point in the exploration of Saleor apps.
In the `apps` folder, you will find the following applications:
- [crm](https://docs.saleor.io/docs/3.x/developer/app-store/apps/crm) - exports customers from Saleor to CRM.
- [cms](./apps/cms) - exports products from Saleor to CMS.
- [data-importer](./apps/data-importer) - import data from CSV to Saleor.
- [emails-and-messages](./apps/emails-and-messages) - notifications and email communication with customers.
- [invoices](./apps/invoices) - generate invoice PDF for each order.
- [klaviyo](./apps/klaviyo) - send Saleor events to Klaviyo, where you can notify the customers.
- [emails-and-messages](./apps/emails-and-messages) - notifications and email communication with customers.
- [monitoring](./apps/monitoring) - send Saleor logs to 3rd party Monitoring services
- [products-feed](./apps/products-feed) - generate products feed XML
- [search](./apps/search) - connect Saleor with search engines.
- [slack](./apps/slack) - get notifications on Slack channel from Saleor events.
- [taxes](https://docs.saleor.io/docs/3.x/developer/app-store/apps/taxes) - calculate order and checkout taxes using external services.
- [cms](./apps/cms) - exports products from Saleor to CMS.
## Development

View file

@ -7,4 +7,4 @@ APL=
REST_APL_ENDPOINT=
REST_APL_TOKEN=
APP_DEBUG=debug # Pino logger levels
APP_LOG_LEVEL=info

View file

@ -30,8 +30,6 @@
"graphql": "^16.6.0",
"graphql-tag": "^2.12.6",
"next": "13.3.0",
"pino": "^8.8.0",
"pino-pretty": "^9.1.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.39.1",

View file

@ -9,14 +9,15 @@ import {
ProductResponseSuccess,
} from "../types";
import { getCmsIdFromSaleorItem } from "./metadata";
import { logger as pinoLogger } from "../../logger";
import { createLogger } from "@saleor/apps-shared";
import { CMSProvider, cmsProviders } from "../providers";
import { ProviderInstanceSchema, providersSchemaSet } from "../config";
export const pingProviderInstance = async (
providerInstanceSettings: ProviderInstanceSchema
): Promise<BaseResponse> => {
const logger = pinoLogger.child({ providerInstanceSettings });
const logger = createLogger({ providerInstanceSettings });
logger.debug("Ping provider instance called");
const provider = cmsProviders[
@ -57,7 +58,8 @@ const executeCmsClientOperation = async ({
cmsClient: CmsClientOperations;
productVariant: WebhookProductVariantFragment;
}): Promise<CmsClientOperationResult | undefined> => {
const logger = pinoLogger.child({ cmsClient });
const logger = createLogger({ cmsClient });
logger.debug("Execute CMS client operation called");
const cmsId = getCmsIdFromSaleorItem(productVariant, cmsClient.cmsProviderInstanceId);
@ -84,9 +86,11 @@ const executeCmsClientOperation = async ({
try {
await cmsClient.operations.updateProduct({
// todo: change params of product methods because of below:
// * In some CMSes, cmsId may be productId. Perhaps it's better to just pass everything as one big object
// * and decide on the id on the provider level.
/*
* todo: change params of product methods because of below:
* * In some CMSes, cmsId may be productId. Perhaps it's better to just pass everything as one big object
* * and decide on the id on the provider level.
*/
id: cmsId,
input: {
saleorId: productVariant.id,
@ -163,7 +167,8 @@ export const executeCmsClientBatchOperation = async ({
productVariant: WebhookProductVariantFragment
) => boolean;
}): Promise<CmsClientBatchOperationResult | undefined> => {
const logger = pinoLogger.child({ cmsClient });
const logger = createLogger({ cmsClient });
logger.debug({ operations: cmsClient.operations }, "Execute CMS client operation called");
if (cmsClient.operationType === "createBatchProducts") {

View file

@ -9,9 +9,10 @@ import {
import { providersSchemaSet } from "../config";
import { CMSProvider, cmsProviders } from "../providers";
import { CmsClientOperations } from "../types";
import { logger as pinoLogger } from "../../logger";
import { getCmsIdFromSaleorItemKey } from "./metadata";
import { type Client } from "urql";
import { createLogger } from "@saleor/apps-shared";
type WebhookContext = Parameters<NextWebhookApiHandler>["2"];
@ -26,7 +27,7 @@ export const createCmsOperations = async ({
productVariantChannels: string[];
productVariantCmsKeys: string[];
}) => {
const logger = pinoLogger.child({
const logger = createLogger({
productVariantChannels,
productVariantCmsKeys,
});

View file

@ -1,10 +1,10 @@
import { v4 as uuidv4 } from "uuid";
import { ContentfulConfig, contentfulConfigSchema } from "../config";
import { logger as pinoLogger } from "../../logger";
import { CreateOperations, ProductResponse, ProductInput } from "../types";
import { createProvider } from "./create";
import { fetchWithRateLimit } from "../data-sync";
import { createLogger } from "@saleor/apps-shared";
const contentfulFetch = (endpoint: string, config: ContentfulConfig, options?: RequestInit) => {
const baseUrl = config.baseUrl || "https://api.contentful.com";
@ -64,6 +64,7 @@ const transformInputToBody = ({
},
},
};
return body;
};
@ -95,7 +96,7 @@ const getEntryEndpoint = ({
}): string => `/spaces/${spaceId}/environments/${environment}/entries/${resourceId}`;
const contentfulOperations: CreateOperations<ContentfulConfig> = (config) => {
const logger = pinoLogger.child({ cms: "strapi" });
const logger = createLogger({ cms: "strapi" });
const { environment, spaceId, contentId, locale, apiRequestsPerSecond } = config;
@ -104,6 +105,7 @@ const contentfulOperations: CreateOperations<ContentfulConfig> = (config) => {
const pingCMS = async () => {
const endpoint = `/spaces/${spaceId}`;
const response = await contentfulFetch(endpoint, config, { method: "GET" });
logger.debug({ response }, "pingCMS response");
return {
ok: response.ok,
@ -126,8 +128,10 @@ const contentfulOperations: CreateOperations<ContentfulConfig> = (config) => {
"X-Contentful-Content-Type": contentId,
},
});
logger.debug({ response }, "createProduct response");
const json = await response.json();
return {
...json,
statusCode: response.status,
@ -144,8 +148,10 @@ const contentfulOperations: CreateOperations<ContentfulConfig> = (config) => {
});
const getEntryResponse = await contentfulFetch(endpoint, config, { method: "GET" });
logger.debug({ getEntryResponse }, "updateProduct getEntryResponse");
const entry = await getEntryResponse.json();
logger.debug({ entry }, "updateProduct entry");
const response = await contentfulFetch(endpoint, config, {
@ -155,8 +161,10 @@ const contentfulOperations: CreateOperations<ContentfulConfig> = (config) => {
"X-Contentful-Version": entry.sys.version,
},
});
logger.debug({ response }, "updateProduct response");
const json = await response.json();
return {
...json,
statusCode: response.status,
@ -178,6 +186,7 @@ const contentfulOperations: CreateOperations<ContentfulConfig> = (config) => {
// Retry with delay x2 if by any chance hit rate limit with HTTP 429
let secondResults: ContentfulResponse[] = [];
if (failedWithLimitResults.length > 0) {
logger.debug("createBatchProductsInCMS retrying failed by rate limit with delay x2");
secondResults = await fetchWithRateLimit(
@ -199,6 +208,7 @@ const contentfulOperations: CreateOperations<ContentfulConfig> = (config) => {
// Retry with delay x2 if by any chance hit rate limit with HTTP 429
let secondResults: Response[] = [];
if (failedWithLimitResults.length > 0) {
logger.debug("deleteBatchProductsInCMS retrying failed by rate limit with delay x2");
secondResults = await fetchWithRateLimit(
@ -214,36 +224,42 @@ const contentfulOperations: CreateOperations<ContentfulConfig> = (config) => {
return {
ping: async () => {
const response = await pingCMS();
logger.debug({ response }, "ping response");
return response;
},
createProduct: async ({ input }) => {
const result = await createProductInCMS(input);
logger.debug({ result }, "createProduct result");
return transformCreateProductResponse(result);
},
updateProduct: async ({ id, input }) => {
const result = await updateProductInCMS(id, input);
logger.debug({ result }, "updateProduct result");
return result;
},
deleteProduct: async ({ id }) => {
const response = await deleteProductInCMS(id);
logger.debug({ response }, "deleteProduct response");
return response;
},
createBatchProducts: async ({ input }) => {
const results = await createBatchProductsInCMS(input);
logger.debug({ results }, "createBatchProducts results");
return results.map((result) => transformCreateProductResponse(result));
},
deleteBatchProducts: async ({ ids }) => {
const results = await deleteBatchProductsInCMS(ids);
logger.debug({ results }, "deleteBatchProducts results");
},
};

View file

@ -1,9 +1,9 @@
import { createProvider } from "./create";
import { CreateOperations, ProductInput, ProductResponse } from "../types";
import { logger as pinoLogger } from "../../logger";
import { ApiError, buildClient, SimpleSchemaTypes } from "@datocms/cma-client-node";
import { DatocmsConfig, datocmsConfigSchema } from "../config";
import { createLogger } from "@saleor/apps-shared";
const datocmsClient = (config: DatocmsConfig, options?: RequestInit) => {
const { baseUrl, token, environment } = config;
@ -46,7 +46,7 @@ const transformResponseItem = (
};
const datocmsOperations: CreateOperations<DatocmsConfig> = (config) => {
const logger = pinoLogger.child({ cms: "strapi" });
const logger = createLogger({ cms: "strapi" });
const client = datocmsClient(config);
@ -96,6 +96,7 @@ const datocmsOperations: CreateOperations<DatocmsConfig> = (config) => {
ping: async () => {
try {
const response = await pingCMS();
logger.debug({ response }, "ping response");
if (!response.id) {
@ -110,6 +111,7 @@ const datocmsOperations: CreateOperations<DatocmsConfig> = (config) => {
createProduct: async ({ input }) => {
try {
const item = await createProductInCMS(input);
logger.debug({ item }, "createProduct response");
return transformResponseItem(item, input);
@ -119,20 +121,24 @@ const datocmsOperations: CreateOperations<DatocmsConfig> = (config) => {
},
updateProduct: async ({ id, input }) => {
const item = await updateProductInCMS(id, input);
logger.debug({ item }, "updateProduct response");
},
deleteProduct: async ({ id }) => {
const item = await deleteProductInCMS(id);
logger.debug({ item }, "deleteProduct response");
},
createBatchProducts: async ({ input }) => {
const items = await createBatchProductsInCMS(input);
logger.debug({ items }, "createBatchProducts response");
return items.map((item) => transformResponseItem(item.id, item.input));
},
deleteBatchProducts: async ({ ids }) => {
const items = await deleteBatchProductsInCMS(ids);
logger.debug({ items }, "deleteBatchProducts response");
},
};

View file

@ -1,7 +1,7 @@
import { StrapiConfig, strapiConfigSchema } from "../config";
import { CreateOperations, ProductResponse, ProductInput } from "../types";
import { createProvider } from "./create";
import { logger as pinoLogger } from "../../logger";
import { createLogger } from "@saleor/apps-shared";
const strapiFetch = async (endpoint: string, config: StrapiConfig, options?: RequestInit) => {
const { baseUrl, token } = config;
@ -31,6 +31,7 @@ const transformInputToBody = (input: ProductInput): StrapiBody => {
product_slug: input.productSlug,
},
};
return body;
};
@ -78,7 +79,7 @@ const transformCreateProductResponse = (
type CreateStrapiOperations = CreateOperations<StrapiConfig>;
export const strapiOperations: CreateStrapiOperations = (config) => {
const logger = pinoLogger.child({ cms: "strapi" });
const logger = createLogger({ cms: "strapi" });
const { contentTypeId } = config;
@ -86,6 +87,7 @@ export const strapiOperations: CreateStrapiOperations = (config) => {
const response = await strapiFetch(`/${contentTypeId}`, config, {
method: "GET",
});
logger.debug({ response }, "pingCMS response");
return { ok: response.ok };
};
@ -96,12 +98,14 @@ export const strapiOperations: CreateStrapiOperations = (config) => {
method: "POST",
body: JSON.stringify(body),
});
logger.debug({ response }, "createProduct response");
return await response.json();
};
const updateProductInCMS = async (id: string, input: ProductInput) => {
const body = transformInputToBody(input);
return await strapiFetch(`/${contentTypeId}/${id}`, config, {
method: "PUT",
body: JSON.stringify(body),
@ -130,36 +134,42 @@ export const strapiOperations: CreateStrapiOperations = (config) => {
return {
ping: async () => {
const response = await pingCMS();
logger.debug({ response }, "ping response");
return response;
},
createProduct: async ({ input }) => {
const result = await createProductInCMS(input);
logger.debug({ result }, "createProduct result");
return transformCreateProductResponse(result, input);
},
updateProduct: async ({ id, input }) => {
const response = await updateProductInCMS(id, input);
logger.debug({ response }, "updateProduct response");
return response;
},
deleteProduct: async ({ id }) => {
const response = await deleteProductInCMS(id);
logger.debug({ response }, "deleteProduct response");
return response;
},
createBatchProducts: async ({ input }) => {
const results = await createBatchProductsInCMS(input);
logger.debug({ results }, "createBatchProducts results");
return results.map((result) => transformCreateProductResponse(result.response, result.input));
},
deleteBatchProducts: async ({ ids }) => {
const responses = await deleteBatchProductsInCMS(ids);
logger.debug({ responses }, "deleteBatchProducts responses");
return responses;

View file

@ -8,14 +8,16 @@ import {
FetchProductVariantMetadataQuery,
UpdateAppMetadataDocument,
} from "../../generated/graphql";
import { logger as pinoLogger } from "../lib/logger";
import { createLogger } from "@saleor/apps-shared";
// 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
// which can be used by the manager.
// Result of this query is cached by the manager.
/*
* 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
* which can be used by the manager.
* Result of this query is cached by the manager.
*/
export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]> {
const logger = pinoLogger.child({
const logger = createLogger({
function: "fetchAllMetadata",
});
@ -31,11 +33,13 @@ export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]>
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.
// The manager will use updated entries returned by this mutation to update it's cache.
/*
* 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.
* The manager will use updated entries returned by this mutation to update it's cache.
*/
export async function mutateMetadata(client: Client, metadata: MetadataEntry[]) {
const logger = pinoLogger.child({
const logger = createLogger({
function: "mutateMetadata",
});
@ -79,9 +83,11 @@ export async function mutateMetadata(client: Client, metadata: MetadataEntry[])
}
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.
// If your use case require plain text values, you can use MetadataManager.
/*
* EncryptedMetadataManager gives you interface to manipulate metadata and cache values in memory.
* 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({
// Secret key should be randomly created for production and set as environment variable
encryptionKey: process.env.SECRET_KEY!,
@ -94,7 +100,7 @@ export async function fetchProductVariantMetadata(
client: Client,
productId: string
): Promise<MetadataEntry[]> {
const logger = pinoLogger.child({
const logger = createLogger({
function: "fetchProductVariantMetadata",
productId,
});

View file

@ -1,11 +1,12 @@
import { NextProtectedApiHandler, createProtectedHandler } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../../saleor-app";
import type { NextApiRequest, NextApiResponse } from "next";
import { logger as pinoLogger } from "../../lib/logger";
import { createClient } from "../../lib/graphql";
import { createSettingsManager } from "../../lib/metadata";
import { getProviderInstancesSettings } from "../../lib/cms/client/settings";
import { pingProviderInstance } from "../../lib/cms/client/clients-execution";
import { createLogger } from "@saleor/apps-shared";
export interface ProviderInstancePingApiPayload {
providerInstanceId: string;
@ -23,9 +24,10 @@ const handler: NextProtectedApiHandler = async (
const { authData } = context;
const { providerInstanceId } = req.body as ProviderInstancePingApiPayload;
const logger = pinoLogger.child({
const logger = createLogger({
endpoint: "ping-provider-instance",
});
logger.debug({ providerInstanceId }, "Called endpoint ping-provider-instance");
if (req.method !== "POST") {

View file

@ -6,11 +6,12 @@ import { executeCmsClientBatchOperation } from "../../lib/cms/client/clients-exe
import { getChannelsSettings, getProviderInstancesSettings } from "../../lib/cms/client/settings";
import { providersSchemaSet } from "../../lib/cms/config/providers";
import { cmsProviders, CMSProvider } from "../../lib/cms/providers";
import { logger as pinoLogger } from "../../lib/logger";
import { createClient } from "../../lib/graphql";
import { createSettingsManager } from "../../lib/metadata";
import { batchUpdateMetadata, MetadataRecord } from "../../lib/cms/client/metadata-execution";
import { CmsBatchOperations } from "../../lib/cms/types";
import { createLogger } from "@saleor/apps-shared";
export interface SyncProductsVariantsApiPayload {
channelSlug: string;
@ -35,7 +36,7 @@ const handler: NextProtectedApiHandler = async (
) => {
const { authData } = context;
const logger = pinoLogger.child({
const logger = createLogger({
endpoint: "sync-products-variants",
});

View file

@ -8,10 +8,11 @@ import { saleorApp } from "../../../../saleor-app";
import { getCmsKeysFromSaleorItem } from "../../../lib/cms/client/metadata";
import { getChannelsSlugsFromSaleorItem } from "../../../lib/cms/client/channels";
import { createCmsOperations, executeCmsOperations, updateMetadata } from "../../../lib/cms/client";
import { logger as pinoLogger } from "../../../lib/logger";
import { createClient } from "../../../lib/graphql";
import { fetchProductVariantMetadata } from "../../../lib/metadata";
import { isAppWebhookIssuer } from "./_utils";
import { createLogger } from "@saleor/apps-shared";
export const config = {
api: {
@ -58,9 +59,10 @@ export const handler: NextWebhookApiHandler<ProductUpdatedWebhookPayloadFragment
const { product, issuingPrincipal } = context.payload;
const { saleorApiUrl, token, appId } = context.authData;
const logger = pinoLogger.child({
const logger = createLogger({
product,
});
logger.debug("Called webhook PRODUCT_UPDATED");
logger.debug({ issuingPrincipal }, "Issuing principal");
@ -99,9 +101,11 @@ export const handler: NextWebhookApiHandler<ProductUpdatedWebhookPayloadFragment
productVariantChannels: productVariantChannels,
productVariantCmsKeys: productVariantCmsKeys,
});
// Do not touch product variants which are not created or should be deleted.
// These operations should and will be performed by PRODUCT_VARIANT_CREATED and PRODUCT_VARIANT_DELETED webhooks.
// Otherwise we will end up with duplicated product variants in CMS providers! (or failed variant delete operations).
/*
* Do not touch product variants which are not created or should be deleted.
* These operations should and will be performed by PRODUCT_VARIANT_CREATED and PRODUCT_VARIANT_DELETED webhooks.
* Otherwise we will end up with duplicated product variants in CMS providers! (or failed variant delete operations).
*/
const cmsUpdateOperations = cmsOperations.filter(
(operation) => operation.operationType === "updateProduct"
);

View file

@ -7,10 +7,11 @@ import {
import { saleorApp } from "../../../../saleor-app";
import { getChannelsSlugsFromSaleorItem } from "../../../lib/cms/client/channels";
import { createCmsOperations, executeCmsOperations, updateMetadata } from "../../../lib/cms/client";
import { logger as pinoLogger } from "../../../lib/logger";
import { createClient } from "../../../lib/graphql";
import { fetchProductVariantMetadata } from "../../../lib/metadata";
import { getCmsKeysFromSaleorItem } from "../../../lib/cms/client/metadata";
import { createLogger } from "@saleor/apps-shared";
export const config = {
api: {
@ -53,9 +54,10 @@ export const handler: NextWebhookApiHandler<ProductVariantCreatedWebhookPayloadF
const { productVariant } = context.payload;
const { saleorApiUrl, token } = context.authData;
const logger = pinoLogger.child({
const logger = createLogger({
productVariant,
});
logger.debug("Called webhook PRODUCT_VARIANT_CREATED");
if (!productVariant) {

View file

@ -7,8 +7,9 @@ import {
import { saleorApp } from "../../../../saleor-app";
import { getCmsKeysFromSaleorItem } from "../../../lib/cms/client/metadata";
import { createCmsOperations, executeCmsOperations, updateMetadata } from "../../../lib/cms/client";
import { logger as pinoLogger } from "../../../lib/logger";
import { createClient } from "../../../lib/graphql";
import { createLogger } from "@saleor/apps-shared";
export const config = {
api: {
@ -51,9 +52,10 @@ export const handler: NextWebhookApiHandler<ProductVariantDeletedWebhookPayloadF
const { productVariant } = context.payload;
const { saleorApiUrl, token } = context.authData;
const logger = pinoLogger.child({
const logger = createLogger({
productVariant,
});
logger.debug("Called webhook PRODUCT_VARIANT_DELETED");
if (!productVariant) {

View file

@ -8,10 +8,11 @@ import { saleorApp } from "../../../../saleor-app";
import { getCmsKeysFromSaleorItem } from "../../../lib/cms/client/metadata";
import { getChannelsSlugsFromSaleorItem } from "../../../lib/cms/client/channels";
import { createCmsOperations, executeCmsOperations, updateMetadata } from "../../../lib/cms/client";
import { logger as pinoLogger } from "../../../lib/logger";
import { createClient } from "../../../lib/graphql";
import { fetchProductVariantMetadata } from "../../../lib/metadata";
import { isAppWebhookIssuer } from "./_utils";
import { createLogger } from "@saleor/apps-shared";
export const config = {
api: {
@ -59,9 +60,10 @@ export const handler: NextWebhookApiHandler<ProductVariantUpdatedWebhookPayloadF
const { productVariant, issuingPrincipal } = context.payload;
const { saleorApiUrl, token, appId } = context.authData;
const logger = pinoLogger.child({
const logger = createLogger({
productVariant,
});
logger.debug("Called webhook PRODUCT_VARIANT_UPDATED");
logger.debug({ issuingPrincipal }, "Issuing principal");

View file

@ -5,7 +5,7 @@
"build": {
"env": [
"APL",
"APP_DEBUG",
"APP_LOG_LEVEL",
"NODE_ENV",
"SECRET_KEY",
"PORT",

View file

@ -9,4 +9,4 @@ REST_APL_TOKEN=
MAILCHIMP_CLIENT_ID=
MAILCHIMP_CLIENT_SECRET=
APP_DEBUG=info
APP_LOG_LEVEL=debug

View file

@ -33,8 +33,6 @@
"jsdom": "^20.0.3",
"next": "13.3.0",
"next-urql": "^4.0.2",
"pino": "^8.8.0",
"pino-pretty": "^9.1.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.0",

View file

@ -1,17 +0,0 @@
import pino from "pino";
export const logger = pino({
level: "debug",
redact: ["token"],
transport:
process.env.NODE_ENV === "development"
? {
target: "pino-pretty",
options: {
colorize: true,
},
}
: undefined,
});
export const createLogger = logger.child.bind(logger);

View file

@ -1,10 +1,11 @@
import { router } from "../trpc/trpc-server";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { createLogger } from "../../lib/logger";
import { MailchimpClientOAuth } from "./mailchimp-client";
import { MailchimpConfigSettingsManager } from "./mailchimp-config-settings-manager";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { createLogger } from "@saleor/apps-shared";
const AddContactSchema = z.object({
listId: z.string().min(1),

View file

@ -2,7 +2,7 @@ import { Client } from "urql";
import { createSettingsManager } from "../../lib/metadata-manager";
import { SettingsManager } from "@saleor/app-sdk/settings-manager";
import { z } from "zod";
import { createLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
export const CustomerCreatedEventConfig = z
.object({

View file

@ -1,6 +1,6 @@
import { router } from "../trpc/trpc-server";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { createLogger } from "../../lib/logger";
import { MailchimpClientOAuth } from "./mailchimp-client";
import {
CustomerCreatedEventConfig,
@ -9,6 +9,7 @@ import {
} from "./mailchimp-config-settings-manager";
import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { createLogger } from "@saleor/apps-shared";
const setTokenInput = MailchimpConfig;

View file

@ -1,7 +1,7 @@
import { MailchimpAuthFrame } from "../../auth/mailchimp-auth-frame/mailchimp-auth-frame";
import React, { useEffect } from "react";
import { trpcClient } from "../../../trpc/trpc-client";
import { createLogger } from "../../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
const logger = createLogger({});

View file

@ -3,8 +3,11 @@ import { middleware, procedure } from "./trpc-server";
import { TRPCError } from "@trpc/server";
import { ProtectedHandlerError } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../saleor-app";
import { logger } from "../../lib/logger";
import { createClient } from "../../lib/create-graphq-client";
import { createLogger } from "@saleor/apps-shared";
const logger = createLogger({ service: "protected-client-procedure" });
const attachAppToken = middleware(async ({ ctx, next }) => {
logger.debug("attachAppToken middleware");

View file

@ -1,6 +1,6 @@
import { NextApiHandler } from "next";
import { MailchimpClientOAuth } from "../../../../modules/mailchimp/mailchimp-client";
import { createLogger } from "../../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
export const getBaseUrl = (headers: { [name: string]: string | string[] | undefined }): string => {
const { host, "x-forwarded-proto": protocol = "http" } = headers;

View file

@ -1,8 +1,9 @@
import { NextApiHandler } from "next";
import { createLogger } from "../../../../lib/logger";
import { processSaleorProtectedHandler } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../../../saleor-app";
import { SALEOR_API_URL_HEADER, SALEOR_AUTHORIZATION_BEARER_HEADER } from "@saleor/app-sdk/const";
import { createLogger } from "@saleor/apps-shared";
export const getBaseUrl = (headers: { [name: string]: string | string[] | undefined }): string => {
const { host, "x-forwarded-proto": protocol = "http" } = headers;

View file

@ -1,6 +1,5 @@
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import {
CustomerCreatedDocument,
CustomerCreatedPayloadFragment,
@ -9,6 +8,7 @@ import { createClient } from "../../../lib/create-graphq-client";
import { MailchimpConfigSettingsManager } from "../../../modules/mailchimp/mailchimp-config-settings-manager";
import { MailchimpClientOAuth } from "../../../modules/mailchimp/mailchimp-client";
import { metadataToMailchimpTags } from "../../../modules/saleor-customers-sync/metadata-to-mailchimp-tags";
import { createLogger } from "@saleor/apps-shared";
export const customerCreatedWebhook = new SaleorAsyncWebhook<CustomerCreatedPayloadFragment>({
name: "Customer Created in Saleor",
@ -24,7 +24,7 @@ export const customerCreatedHandler: NextWebhookApiHandler<CustomerCreatedPayloa
res,
context
) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: customerCreatedWebhook.name,
});

View file

@ -1,6 +1,6 @@
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import {
CustomerUpdatedDocument,
CustomerUpdatedPayloadFragment,
@ -9,6 +9,7 @@ import { createClient } from "../../../lib/create-graphq-client";
import { MailchimpConfigSettingsManager } from "../../../modules/mailchimp/mailchimp-config-settings-manager";
import { MailchimpClientOAuth } from "../../../modules/mailchimp/mailchimp-client";
import { metadataToMailchimpTags } from "../../../modules/saleor-customers-sync/metadata-to-mailchimp-tags";
import { createLogger } from "@saleor/apps-shared";
export const customerMetadataUpdatedWebhook =
new SaleorAsyncWebhook<CustomerUpdatedPayloadFragment>({
@ -24,7 +25,7 @@ const handler: NextWebhookApiHandler<CustomerUpdatedPayloadFragment> = async (
res,
context
) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: customerMetadataUpdatedWebhook.name,
});

View file

@ -42,8 +42,6 @@
"next": "13.3.0",
"next-urql": "^4.0.3",
"nodemailer": "^6.9.1",
"pino": "^8.8.0",
"pino-pretty": "^9.1.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.0",

View file

@ -1,19 +0,0 @@
import pino from "pino";
/**
* TODO Set up log drain etc
*/
export const logger = pino({
level: "debug",
transport:
process.env.NODE_ENV === "development"
? {
target: "pino-pretty",
options: {
colorize: true,
},
}
: undefined,
});
export const createLogger = logger.child.bind(logger);

View file

@ -1,4 +1,4 @@
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
appChannelConfigurationInputSchema,
appConfigInputSchema,
@ -8,8 +8,10 @@ import { router } from "../trpc/trpc-server";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { z } from "zod";
// Allow access only for the dashboard users and attaches the
// configuration service to the context
/*
* Allow access only for the dashboard users and attaches the
* configuration service to the context
*/
const protectedWithConfigurationService = protectedClientProcedure.use(({ next, ctx }) =>
next({
ctx: {
@ -26,7 +28,8 @@ export const appConfigurationRouter = router({
getChannelConfiguration: protectedWithConfigurationService
.input(z.object({ channelSlug: z.string() }))
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("Get Channel Configuration called");
return await ctx.configurationService.getChannelConfiguration(input.channelSlug);
@ -36,13 +39,14 @@ export const appConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(appChannelConfigurationInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("Set channel configuration called");
await ctx.configurationService.setChannelConfiguration(input);
}),
fetch: protectedWithConfigurationService.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("appConfigurationRouter.fetch called");
@ -55,7 +59,7 @@ export const appConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(appConfigInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "appConfigurationRouter.setAndReplace called with input");

View file

@ -1,11 +1,11 @@
import { PrivateMetadataAppConfigurator } from "./app-configurator";
import { Client } from "urql";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { AppConfig, AppConfigurationPerChannel } from "./app-config";
import { getDefaultEmptyAppConfiguration } from "./app-config-container";
import { createSettingsManager } from "../../lib/metadata-manager";
const logger = pinoLogger.child({
const logger = createLogger({
service: "AppConfigurationService",
});
@ -25,6 +25,7 @@ export class AppConfigurationService {
logger.debug("Fetch configuration from Saleor API");
const config = await this.metadataConfigurator.getConfig();
this.configurationData = config;
}
@ -64,11 +65,13 @@ export class AppConfigurationService {
async getChannelConfiguration(channel: string) {
logger.debug("Get channel configuration");
const configurations = await this.getConfiguration();
if (!configurations) {
return getDefaultEmptyAppConfiguration();
}
const channelConfiguration = configurations.configurationsPerChannel[channel];
return channelConfiguration || getDefaultEmptyAppConfiguration();
}
@ -81,6 +84,7 @@ export class AppConfigurationService {
}) {
logger.debug("Set channel configuration");
let configurations = await this.getConfiguration();
if (!configurations) {
configurations = { configurationsPerChannel: {} };
}

View file

@ -1,6 +1,6 @@
import { AuthData } from "@saleor/app-sdk/APL";
import { Client } from "urql";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { AppConfigurationService } from "../app-configuration/get-app-configuration.service";
import { MjmlConfigurationService } from "../mjml/configuration/get-mjml-configuration.service";
import { sendMjml } from "../mjml/send-mjml";
@ -25,7 +25,7 @@ export const sendEventMessages = async ({
payload,
client,
}: SendEventMessagesArgs) => {
const logger = pinoLogger.child({
const logger = createLogger({
fn: "sendEventMessages",
});
@ -60,6 +60,7 @@ export const sendEventMessages = async ({
const mjmlConfiguration = await mjmlConfigurationService.getConfiguration({
id: channelAppConfiguration.mjmlConfigurationId,
});
if (mjmlConfiguration) {
const mjmlStatus = await sendMjml({
event,
@ -86,6 +87,7 @@ export const sendEventMessages = async ({
const sendgridConfiguration = await sendgridConfigurationService.getConfiguration({
id: channelAppConfiguration.sendgridConfigurationId,
});
if (sendgridConfiguration) {
const sendgridStatus = await sendSendgrid({
event,

View file

@ -1,7 +1,7 @@
import Handlebars from "handlebars";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
const logger = pinoLogger.child({
const logger = createLogger({
fn: "compileHandlebarsTemplate",
});
@ -10,6 +10,7 @@ export const compileHandlebarsTemplate = (template: string, variables: any) => {
try {
const templateDelegate = Handlebars.compile(template);
const htmlTemplate = templateDelegate(variables);
logger.debug("Template successfully compiled");
return {
template: htmlTemplate,

View file

@ -1,7 +1,7 @@
import mjml2html from "mjml";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
const logger = pinoLogger.child({
const logger = createLogger({
fn: "compileMjml",
});

View file

@ -1,11 +1,11 @@
import { MjmlConfigurator, PrivateMetadataMjmlConfigurator } from "./mjml-configurator";
import { Client } from "urql";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { MjmlConfig, MjmlConfiguration } from "./mjml-config";
import { FilterConfigurationsArgs, MjmlConfigContainer } from "./mjml-config-container";
import { createSettingsManager } from "../../../lib/metadata-manager";
const logger = pinoLogger.child({
const logger = createLogger({
service: "MjmlConfigurationService",
});
@ -29,6 +29,7 @@ export class MjmlConfigurationService {
logger.debug("Fetch configuration from Saleor API");
const config = await this.metadataConfigurator.getConfig();
this.configurationData = config;
}
@ -82,6 +83,7 @@ export class MjmlConfigurationService {
const updatedConfigurationRoot = MjmlConfigContainer.createConfiguration(
await this.getConfigurationRoot()
)(config);
await this.setConfigurationRoot(updatedConfigurationRoot);
return updatedConfigurationRoot.configurations[
@ -94,6 +96,7 @@ export class MjmlConfigurationService {
const updatedConfigurationRoot = MjmlConfigContainer.updateConfiguration(
await this.getConfigurationRoot()
)(config);
this.setConfigurationRoot(updatedConfigurationRoot);
}
@ -102,6 +105,7 @@ export class MjmlConfigurationService {
const updatedConfigurationRoot = MjmlConfigContainer.deleteConfiguration(
await this.getConfigurationRoot()
)({ id });
this.setConfigurationRoot(updatedConfigurationRoot);
}
}

View file

@ -1,4 +1,4 @@
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
mjmlCreateConfigurationSchema,
mjmlDeleteConfigurationInputSchema,
@ -16,8 +16,10 @@ import { compileMjml } from "../compile-mjml";
import Handlebars from "handlebars";
import { TRPCError } from "@trpc/server";
// Allow access only for the dashboard users and attaches the
// configuration service to the context
/*
* Allow access only for the dashboard users and attaches the
* configuration service to the context
*/
const protectedWithConfigurationService = protectedClientProcedure.use(({ next, ctx }) =>
next({
ctx: {
@ -32,7 +34,8 @@ const protectedWithConfigurationService = protectedClientProcedure.use(({ next,
export const mjmlConfigurationRouter = router({
fetch: protectedWithConfigurationService.query(async ({ ctx }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("mjmlConfigurationRouter.fetch called");
return ctx.configurationService.getConfigurationRoot();
}),
@ -40,7 +43,8 @@ export const mjmlConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlGetConfigurationInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.get called");
return ctx.configurationService.getConfiguration(input);
}),
@ -48,7 +52,8 @@ export const mjmlConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlGetConfigurationsInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.getConfigurations called");
return ctx.configurationService.getConfigurations(input);
}),
@ -56,7 +61,8 @@ export const mjmlConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlCreateConfigurationSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.create called");
return await ctx.configurationService.createConfiguration(input);
}),
@ -64,9 +70,11 @@ export const mjmlConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlDeleteConfigurationInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.delete called");
const existingConfiguration = await ctx.configurationService.getConfiguration(input);
if (!existingConfiguration) {
throw new TRPCError({
code: "BAD_REQUEST",
@ -80,14 +88,17 @@ export const mjmlConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlUpdateOrCreateConfigurationSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.update or create called");
const { id } = input;
if (!id) {
return await ctx.configurationService.createConfiguration(input);
} else {
const existingConfiguration = await ctx.configurationService.getConfiguration({ id });
if (!existingConfiguration) {
throw new TRPCError({
code: "BAD_REQUEST",
@ -99,6 +110,7 @@ export const mjmlConfigurationRouter = router({
...input,
events: existingConfiguration.events,
};
await ctx.configurationService.updateConfiguration(configuration);
return configuration;
}
@ -107,7 +119,7 @@ export const mjmlConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlGetEventConfigurationInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.getEventConfiguration or create called");
@ -123,6 +135,7 @@ export const mjmlConfigurationRouter = router({
}
const event = configuration.events.find((e) => e.eventType === input.eventType);
if (!event) {
throw new TRPCError({
code: "BAD_REQUEST",
@ -135,7 +148,7 @@ export const mjmlConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(mjmlUpdateEventConfigurationInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.updateEventConfiguration or create called");
@ -151,6 +164,7 @@ export const mjmlConfigurationRouter = router({
}
const eventIndex = configuration.events.findIndex((e) => e.eventType === input.eventType);
configuration.events[eventIndex] = {
active: input.active,
eventType: input.eventType,
@ -171,7 +185,8 @@ export const mjmlConfigurationRouter = router({
})
)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "mjmlConfigurationRouter.renderTemplate called");
let renderedSubject = "";
@ -180,16 +195,19 @@ export const mjmlConfigurationRouter = router({
if (input.subject) {
const compiledSubjectTemplate = Handlebars.compile(input.subject);
logger.warn("subject part");
renderedSubject = compiledSubjectTemplate(payload);
}
let renderedEmail = "";
if (input.template) {
const compiledSubjectTemplate = Handlebars.compile(input.template);
const templatedEmail = compiledSubjectTemplate(payload);
const { html: rawHtml } = compileMjml(templatedEmail);
if (rawHtml) {
renderedEmail = rawHtml;
}

View file

@ -1,7 +1,7 @@
import { convert } from "html-to-text";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
const logger = pinoLogger.child({
const logger = createLogger({
fn: "htmlToPlaintext",
});
@ -9,6 +9,7 @@ export const htmlToPlaintext = (html: string) => {
logger.debug("Converting HTML template to plaintext");
try {
const plaintext = convert(html);
logger.debug("Converted successfully");
return {
plaintext,

View file

@ -1,7 +1,7 @@
import nodemailer from "nodemailer";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
const logger = pinoLogger.child({
const logger = createLogger({
fn: "sendEmailWithSmtp",
});
@ -33,6 +33,7 @@ export const sendEmailWithSmtp = async ({ smtpSettings, mailData }: SendMailArgs
const response = await transporter.sendMail({
...mailData,
});
logger.debug("An email has been sent");
return { response };
} catch (error) {

View file

@ -1,4 +1,4 @@
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { compileMjml } from "./compile-mjml";
import { compileHandlebarsTemplate } from "./compile-handlebars-template";
import { sendEmailWithSmtp, SendMailArgs } from "./send-email-with-smtp";
@ -26,12 +26,13 @@ export const sendMjml = async ({
event,
mjmlConfiguration,
}: SendMjmlArgs) => {
const logger = pinoLogger.child({
const logger = createLogger({
fn: "sendMjml",
event,
});
const eventSettings = mjmlConfiguration.events.find((e) => e.eventType === event);
if (!eventSettings) {
logger.debug("No active settings for this event, skipping");
return {

View file

@ -1,11 +1,11 @@
import { SendgridConfigurator, PrivateMetadataSendgridConfigurator } from "./sendgrid-configurator";
import { Client } from "urql";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { SendgridConfig, SendgridConfiguration } from "./sendgrid-config";
import { FilterConfigurationsArgs, SendgridConfigContainer } from "./sendgrid-config-container";
import { createSettingsManager } from "../../../lib/metadata-manager";
const logger = pinoLogger.child({
const logger = createLogger({
service: "SendgridConfigurationService",
});
@ -29,6 +29,7 @@ export class SendgridConfigurationService {
logger.debug("Fetch configuration from Saleor API");
const config = await this.metadataConfigurator.getConfig();
this.configurationData = config;
}
@ -82,6 +83,7 @@ export class SendgridConfigurationService {
const updatedConfigurationRoot = SendgridConfigContainer.createConfiguration(
await this.getConfigurationRoot()
)(config);
await this.setConfigurationRoot(updatedConfigurationRoot);
return updatedConfigurationRoot.configurations[
@ -94,6 +96,7 @@ export class SendgridConfigurationService {
const updatedConfigurationRoot = SendgridConfigContainer.updateConfiguration(
await this.getConfigurationRoot()
)(config);
this.setConfigurationRoot(updatedConfigurationRoot);
}
@ -102,6 +105,7 @@ export class SendgridConfigurationService {
const updatedConfigurationRoot = SendgridConfigContainer.deleteConfiguration(
await this.getConfigurationRoot()
)({ id });
this.setConfigurationRoot(updatedConfigurationRoot);
}
}

View file

@ -1,4 +1,4 @@
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
sendgridCreateConfigurationSchema,
sendgridDeleteConfigurationInputSchema,
@ -13,8 +13,10 @@ import { router } from "../../trpc/trpc-server";
import { protectedClientProcedure } from "../../trpc/protected-client-procedure";
import { TRPCError } from "@trpc/server";
// Allow access only for the dashboard users and attaches the
// configuration service to the context
/*
* Allow access only for the dashboard users and attaches the
* configuration service to the context
*/
const protectedWithConfigurationService = protectedClientProcedure.use(({ next, ctx }) =>
next({
ctx: {
@ -29,7 +31,8 @@ const protectedWithConfigurationService = protectedClientProcedure.use(({ next,
export const sendgridConfigurationRouter = router({
fetch: protectedWithConfigurationService.query(async ({ ctx }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("sendgridConfigurationRouter.fetch called");
return ctx.configurationService.getConfigurationRoot();
}),
@ -37,7 +40,8 @@ export const sendgridConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(sendgridGetConfigurationInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "sendgridConfigurationRouter.get called");
return ctx.configurationService.getConfiguration(input);
}),
@ -45,7 +49,8 @@ export const sendgridConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(sendgridGetConfigurationsInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "sendgridConfigurationRouter.getConfigurations called");
return ctx.configurationService.getConfigurations(input);
}),
@ -53,7 +58,8 @@ export const sendgridConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(sendgridCreateConfigurationSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "sendgridConfigurationRouter.create called");
return await ctx.configurationService.createConfiguration(input);
}),
@ -61,9 +67,11 @@ export const sendgridConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(sendgridDeleteConfigurationInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "sendgridConfigurationRouter.delete called");
const existingConfiguration = await ctx.configurationService.getConfiguration(input);
if (!existingConfiguration) {
throw new TRPCError({
code: "BAD_REQUEST",
@ -77,14 +85,17 @@ export const sendgridConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(sendgridUpdateOrCreateConfigurationSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "sendgridConfigurationRouter.update or create called");
const { id } = input;
if (!id) {
return await ctx.configurationService.createConfiguration(input);
} else {
const existingConfiguration = await ctx.configurationService.getConfiguration({ id });
if (!existingConfiguration) {
throw new TRPCError({
code: "BAD_REQUEST",
@ -96,6 +107,7 @@ export const sendgridConfigurationRouter = router({
...input,
events: existingConfiguration.events,
};
await ctx.configurationService.updateConfiguration(configuration);
return configuration;
}
@ -104,7 +116,7 @@ export const sendgridConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(sendgridGetEventConfigurationInputSchema)
.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "sendgridConfigurationRouter.getEventConfiguration or create called");
@ -120,6 +132,7 @@ export const sendgridConfigurationRouter = router({
}
const event = configuration.events.find((e) => e.eventType === input.eventType);
if (!event) {
throw new TRPCError({
code: "BAD_REQUEST",
@ -132,7 +145,7 @@ export const sendgridConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(sendgridUpdateEventConfigurationInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "sendgridConfigurationRouter.updateEventConfiguration or create called");
@ -148,6 +161,7 @@ export const sendgridConfigurationRouter = router({
}
const eventIndex = configuration.events.findIndex((e) => e.eventType === input.eventType);
configuration.events[eventIndex] = {
active: input.active,
eventType: input.eventType,

View file

@ -1,4 +1,4 @@
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { SendgridConfiguration } from "./configuration/sendgrid-config";
import { MailService } from "@sendgrid/mail";
import { MessageEventTypes } from "../event-handlers/message-event-types";
@ -23,10 +23,11 @@ export const sendSendgrid = async ({
event,
sendgridConfiguration,
}: SendSendgridArgs) => {
const logger = pinoLogger.child({
const logger = createLogger({
fn: "sendSendgrid",
event,
});
if (!sendgridConfiguration.senderEmail) {
logger.debug("Sender email has not been specified, skipping");
return {
@ -39,6 +40,7 @@ export const sendSendgrid = async ({
}
const eventSettings = sendgridConfiguration.events.find((e) => e.eventType === event);
if (!eventSettings) {
logger.debug("No active settings for this event, skipping");
return {
@ -74,6 +76,7 @@ export const sendSendgrid = async ({
try {
const mailService = new MailService();
mailService.setApiKey(sendgridConfiguration.apiKey);
await mailService.send({

View file

@ -3,7 +3,7 @@ import { middleware, procedure } from "./trpc-server";
import { TRPCError } from "@trpc/server";
import { ProtectedHandlerError } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../saleor-app";
import { logger } from "../../lib/logger";
import { logger } from "@saleor/apps-shared";
import { createClient } from "../../lib/create-graphql-client";
const attachAppToken = middleware(async ({ ctx, next }) => {

View file

@ -2,7 +2,7 @@ import { createAppRegisterHandler } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../saleor-app";
import { createClient } from "../../lib/create-graphql-client";
import { logger } from "../../lib/logger";
import { logger } from "@saleor/apps-shared";
import { getBaseUrl } from "../../lib/get-base-url";
import { registerNotifyWebhook } from "../../lib/register-notify-webhook";
@ -33,6 +33,7 @@ export default createAppRegisterHandler({
const client = createClient(ctx.authData.saleorApiUrl, async () =>
Promise.resolve({ token: ctx.authData.token })
);
await registerNotifyWebhook({
client: client,
baseUrl: baseUrl,

View file

@ -1,7 +1,7 @@
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { gql } from "urql";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
InvoiceSentWebhookPayloadFragment,
OrderDetailsFragmentDoc,
@ -49,7 +49,7 @@ const handler: NextWebhookApiHandler<InvoiceSentWebhookPayloadFragment> = async
res,
context
) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: invoiceSentWebhook.name,
});
@ -64,6 +64,7 @@ const handler: NextWebhookApiHandler<InvoiceSentWebhookPayloadFragment> = async
}
const recipientEmail = order.userEmail || order.user?.email;
if (!recipientEmail?.length) {
logger.error(`The order ${order.number} had no email recipient set. Aborting.`);
return res

View file

@ -1,12 +1,14 @@
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { sendEventMessages } from "../../../modules/event-handlers/send-event-messages";
import { createClient } from "../../../lib/create-graphql-client";
import { MessageEventTypes } from "../../../modules/event-handlers/message-event-types";
// Notify event handles multiple event types which are recognized based on payload field `notify_event`.
// Handler recognizes if event is one of the supported typed and sends appropriate message.
/*
* Notify event handles multiple event types which are recognized based on payload field `notify_event`.
* Handler recognizes if event is one of the supported typed and sends appropriate message.
*/
interface NotifySubscriptionPayload {
notify_event: string;
@ -62,7 +64,7 @@ export const notifyWebhook = new SaleorAsyncWebhook<NotifySubscriptionPayload>({
});
const handler: NextWebhookApiHandler<NotifySubscriptionPayload> = async (req, res, context) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: notifyWebhook.name,
});
@ -89,6 +91,7 @@ const handler: NextWebhookApiHandler<NotifySubscriptionPayload> = async (req, re
};
const event = notifyEventMapping[payload.notify_event];
if (!event) {
logger.error(`The type of received notify event (${payload.notify_event}) is not supported.`);
return res

View file

@ -1,7 +1,7 @@
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { gql } from "urql";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
OrderCancelledWebhookPayloadFragment,
OrderDetailsFragmentDoc,
@ -40,7 +40,7 @@ const handler: NextWebhookApiHandler<OrderCancelledWebhookPayloadFragment> = asy
res,
context
) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: orderCancelledWebhook.name,
});
@ -55,6 +55,7 @@ const handler: NextWebhookApiHandler<OrderCancelledWebhookPayloadFragment> = asy
}
const recipientEmail = order.userEmail || order.user?.email;
if (!recipientEmail?.length) {
logger.error(`The order ${order.number} had no email recipient set. Aborting.`);
return res

View file

@ -1,7 +1,7 @@
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { gql } from "urql";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
OrderConfirmedWebhookPayloadFragment,
OrderDetailsFragmentDoc,
@ -41,7 +41,7 @@ const handler: NextWebhookApiHandler<OrderConfirmedWebhookPayloadFragment> = asy
res,
context
) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: orderConfirmedWebhook.name,
});
@ -56,6 +56,7 @@ const handler: NextWebhookApiHandler<OrderConfirmedWebhookPayloadFragment> = asy
}
const recipientEmail = order.userEmail || order.user?.email;
if (!recipientEmail?.length) {
logger.error(`The order ${order.number} had no email recipient set. Aborting.`);
return res

View file

@ -2,7 +2,7 @@ import { OrderDetailsFragmentDoc } from "./../../../../generated/graphql";
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { gql } from "urql";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { OrderCreatedWebhookPayloadFragment } from "../../../../generated/graphql";
import { sendEventMessages } from "../../../modules/event-handlers/send-event-messages";
import { createClient } from "../../../lib/create-graphql-client";
@ -38,7 +38,7 @@ const handler: NextWebhookApiHandler<OrderCreatedWebhookPayloadFragment> = async
res,
context
) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: orderCreatedWebhook.name,
});
@ -53,6 +53,7 @@ const handler: NextWebhookApiHandler<OrderCreatedWebhookPayloadFragment> = async
}
const recipientEmail = order.userEmail || order.user?.email;
if (!recipientEmail?.length) {
logger.error(`The order ${order.number} had no email recipient set. Aborting.`);
return res

View file

@ -1,7 +1,7 @@
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { gql } from "urql";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
OrderDetailsFragmentDoc,
OrderFulfilledWebhookPayloadFragment,
@ -41,7 +41,7 @@ const handler: NextWebhookApiHandler<OrderFulfilledWebhookPayloadFragment> = asy
res,
context
) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: orderFulfilledWebhook.name,
});
@ -56,6 +56,7 @@ const handler: NextWebhookApiHandler<OrderFulfilledWebhookPayloadFragment> = asy
}
const recipientEmail = order.userEmail || order.user?.email;
if (!recipientEmail?.length) {
logger.error(`The order ${order.number} had no email recipient set. Aborting.`);
return res

View file

@ -1,7 +1,7 @@
import { NextWebhookApiHandler, SaleorAsyncWebhook } from "@saleor/app-sdk/handlers/next";
import { gql } from "urql";
import { saleorApp } from "../../../saleor-app";
import { logger as pinoLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
OrderDetailsFragmentDoc,
OrderFullyPaidWebhookPayloadFragment,
@ -41,7 +41,7 @@ const handler: NextWebhookApiHandler<OrderFullyPaidWebhookPayloadFragment> = asy
res,
context
) => {
const logger = pinoLogger.child({
const logger = createLogger({
webhook: orderFullyPaidWebhook.name,
});
@ -56,6 +56,7 @@ const handler: NextWebhookApiHandler<OrderFullyPaidWebhookPayloadFragment> = asy
}
const recipientEmail = order.userEmail || order.user?.email;
if (!recipientEmail?.length) {
logger.error(`The order ${order.number} had no email recipient set. Aborting.`);
return res

View file

@ -37,8 +37,6 @@
"graphql-tag": "^2.12.6",
"microinvoice": "^1.0.6",
"next": "13.3.0",
"pino": "^8.8.0",
"pino-pretty": "^9.1.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.41.0",

View file

@ -1,19 +0,0 @@
import pino from "pino";
/**
* TODO Set up log drain etc
*/
export const logger = pino({
level: process.env.APP_DEBUG ?? "silent",
transport:
process.env.NODE_ENV === "development"
? {
target: "pino-pretty",
options: {
colorize: true,
},
}
: undefined,
});
export const createLogger = logger.child.bind(logger);

View file

@ -2,13 +2,13 @@ import { router } from "../trpc/trpc-server";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { PrivateMetadataAppConfigurator } from "./app-configurator";
import { createSettingsManager } from "./metadata-manager";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { appConfigInputSchema } from "./app-config-input-schema";
import { GetAppConfigurationService } from "./get-app-configuration.service";
export const appConfigurationRouter = router({
fetch: protectedClientProcedure.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("appConfigurationRouter.fetch called");
@ -21,7 +21,7 @@ export const appConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(appConfigInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "appConfigurationRouter.setAndReplace called with input");

View file

@ -4,7 +4,7 @@ import { ChannelsFetcher } from "../channels/channels-fetcher";
import { ShopInfoFetcher } from "../shop-info/shop-info-fetcher";
import { FallbackAppConfig } from "./fallback-app-config";
import { Client } from "urql";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
// todo test
export class GetAppConfigurationService {
@ -16,7 +16,7 @@ export class GetAppConfigurationService {
) {}
async getConfiguration() {
const logger = pinoLogger.child({
const logger = createLogger({
service: "GetAppConfigurationService",
saleorApiUrl: this.settings.saleorApiUrl,
});

View file

@ -1,6 +1,6 @@
import { Client, gql } from "urql";
import { InvoiceCreateDocument } from "../../../generated/graphql";
import { logger } from "../../lib/logger";
import { logger } from "@saleor/apps-shared";
gql`
mutation InvoiceCreate($orderId: ID!, $invoiceInput: InvoiceCreateInput!) {

View file

@ -1,7 +1,7 @@
import { join } from "path";
import invariant from "tiny-invariant";
import { mkdir, access, constants } from "fs/promises";
import { logger } from "../../lib/logger";
import { logger } from "@saleor/apps-shared";
/**
* Path will be relative to built file, in dev its inside .next/server

View file

@ -9,7 +9,7 @@ import { FileUploadMutation } from "../../../generated/graphql";
* Use File instead of Blob so Saleor can understand name
*/
import { File } from "@web-std/file";
import { logger } from "../../lib/logger";
import { logger } from "@saleor/apps-shared";
const fileUpload = gql`
mutation FileUpload($file: Upload!) {

View file

@ -4,7 +4,7 @@ import { middleware, procedure } from "./trpc-server";
import { saleorApp } from "../../saleor-app";
import { TRPCError } from "@trpc/server";
import { ProtectedHandlerError } from "@saleor/app-sdk/handlers/next";
import { logger } from "../../lib/logger";
import { logger } from "@saleor/apps-shared";
const attachAppToken = middleware(async ({ ctx, next }) => {
logger.debug("attachAppToken middleware");

View file

@ -4,7 +4,7 @@ import { gql } from "urql";
import { createClient } from "../../lib/graphql";
import { SaleorVersionQuery } from "../../../generated/graphql";
import { createLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { SaleorVersionCompatibilityValidator } from "../../lib/saleor-version-compatibility-validator";
const allowedUrlsPattern = process.env.ALLOWED_DOMAIN_PATTERN;

View file

@ -15,7 +15,7 @@ import {
import { MicroinvoiceInvoiceGenerator } from "../../../modules/invoice-generator/microinvoice/microinvoice-invoice-generator";
import { hashInvoiceFilename } from "../../../modules/invoice-file-name/hash-invoice-filename";
import { resolveTempPdfFileLocation } from "../../../modules/invoice-file-name/resolve-temp-pdf-file-location";
import { createLogger } from "../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { GetAppConfigurationService } from "../../../modules/app-configuration/get-app-configuration.service";
import { SALEOR_API_URL_HEADER } from "@saleor/app-sdk/const";

View file

@ -2,7 +2,6 @@
"name": "saleor-app-klaviyo",
"version": "1.5.0",
"private": true,
"packageManager": "pnpm@7.18.1",
"scripts": {
"dev": "pnpm generate && NODE_OPTIONS='--inspect' next dev",
"build": "pnpm generate && next build",
@ -57,6 +56,6 @@
"postcss": "^8.4.14",
"prettier": "^2.7.1",
"pretty-quick": "^3.1.3",
"typescript": "4.9.5"
"typescript": "5.0.4"
}
}

View file

@ -37,8 +37,6 @@
"jsdom": "^20.0.3",
"next": "13.3.0",
"next-urql": "^4.0.2",
"pino": "^8.8.0",
"pino-pretty": "^9.1.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.0",

View file

@ -1,6 +1,6 @@
import { url } from "inspector";
import { Client } from "urql";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import {
FetchProductDataForFeedDocument,
GoogleFeedProductVariantFragment,
@ -12,7 +12,7 @@ interface FetchProductDataArgs {
}
export const fetchProductData = async ({ client, channel }: FetchProductDataArgs) => {
const logger = pinoLogger.child({ saleorApiUrl: url, channel, route: "Google Product Feed" });
const logger = createLogger({ saleorApiUrl: url, channel, route: "Google Product Feed" });
let result = await client
.query(FetchProductDataForFeedDocument, { channel: channel as string, first: 100 })

View file

@ -1,6 +1,6 @@
import { url } from "inspector";
import { Client } from "urql";
import { logger as pinoLogger } from "../logger";
import { createLogger } from "@saleor/apps-shared";
import { ShopDetailsDocument } from "../../../generated/graphql";
interface FetchShopDataArgs {
@ -9,7 +9,7 @@ interface FetchShopDataArgs {
}
export const fetchShopData = async ({ client, channel }: FetchShopDataArgs) => {
const logger = pinoLogger.child({ saleorApiUrl: url, channel, route: "Google Product Feed" });
const logger = createLogger({ saleorApiUrl: url, channel, route: "Google Product Feed" });
const result = await client.query(ShopDetailsDocument, {}).toPromise();
const shopDetails = result.data?.shop;

View file

@ -1,16 +0,0 @@
import pino from "pino";
export const logger = pino({
level: process.env.APP_DEBUG ?? "silent",
transport:
process.env.NODE_ENV === "development"
? {
target: "pino-pretty",
options: {
colorize: true,
},
}
: undefined,
});
export const createLogger = logger.child.bind(logger);

View file

@ -2,13 +2,13 @@ import { router } from "../trpc/trpc-server";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { PrivateMetadataAppConfigurator } from "./app-configurator";
import { createSettingsManager } from "./metadata-manager";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { appConfigInputSchema } from "./app-config-input-schema";
import { GetAppConfigurationService } from "./get-app-configuration.service";
export const appConfigurationRouter = router({
fetch: protectedClientProcedure.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("appConfigurationRouter.fetch called");
@ -21,7 +21,7 @@ export const appConfigurationRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(appConfigInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug(input, "appConfigurationRouter.setAndReplace called with input");

View file

@ -4,7 +4,7 @@ import { ChannelsFetcher } from "../channels/channels-fetcher";
import { ShopInfoFetcher } from "../shop-info/shop-info-fetcher";
import { FallbackAppConfig } from "./fallback-app-config";
import { Client } from "urql";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
export class GetAppConfigurationService {
constructor(
@ -15,7 +15,7 @@ export class GetAppConfigurationService {
) {}
async getConfiguration() {
const logger = pinoLogger.child({
const logger = createLogger({
service: "GetAppConfigurationService",
saleorApiUrl: this.settings.saleorApiUrl,
});

View file

@ -1,6 +1,6 @@
import { router } from "../trpc/trpc-server";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { SetCategoryMappingInputSchema } from "./category-mapping-input-schema";
import {
FetchCategoriesWithMappingDocument,
@ -13,7 +13,7 @@ export const categoryMappingRouter = router({
* Get all the category mappings to Google categories from its public metadata
*/
getCategoryMappings: protectedClientProcedure.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("categoriesRouter.getCategoryMappings called");
@ -37,7 +37,7 @@ export const categoryMappingRouter = router({
.meta({ requiredClientPermissions: ["MANAGE_APPS"] })
.input(SetCategoryMappingInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ saleorApiUrl: ctx.saleorApiUrl });
const logger = createLogger({ saleorApiUrl: ctx.saleorApiUrl });
logger.debug("categoriesRouter.setCategoryMapping called");
const { error } = await ctx.apiClient

View file

@ -3,7 +3,7 @@ import { middleware, procedure } from "./trpc-server";
import { TRPCError } from "@trpc/server";
import { ProtectedHandlerError } from "@saleor/app-sdk/handlers/next";
import { saleorApp } from "../../saleor-app";
import { logger } from "../../lib/logger";
import { logger } from "@saleor/apps-shared";
import { createClient } from "../../lib/create-graphq-client";
const attachAppToken = middleware(async ({ ctx, next }) => {

View file

@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
import { initUrqlClient } from "next-urql";
import { GoogleFeedProductVariantFragment } from "../../../../../../generated/graphql";
import { apl } from "../../../../../saleor-app";
import { logger as pinoLogger } from "../../../../../lib/logger";
import { createLogger } from "@saleor/apps-shared";
import { fetchProductData } from "../../../../../lib/google-feed/fetch-product-data";
import { getGoogleFeedSettings } from "../../../../../lib/google-feed/get-google-feed-settings";
import { generateGoogleXmlFeed } from "../../../../../lib/google-feed/generate-google-xml-feed";
@ -17,7 +17,7 @@ export const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const url = req.query.url as string;
const channel = req.query.channel as string;
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: url,
channel,
route: "api/feed/{url}/{channel}/google.xml",

View file

@ -30,8 +30,6 @@
"graphql-tag": "^2.12.6",
"next": "13.3.0",
"next-urql": "4.0.0",
"pino": "^8.8.0",
"pino-pretty": "^9.1.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-helmet": "^6.1.0",

View file

@ -1,17 +1,10 @@
import pino from "pino";
import { createLogger as _createLogger } from "@saleor/apps-shared";
export const logger = pino({
level: "debug",
/**
* Extend factory to add more settings specific for the app
*/
export const logger = _createLogger({
redact: ["token", "secretKey"],
transport:
process.env.NODE_ENV === "development"
? {
target: "pino-pretty",
options: {
colorize: true,
},
}
: undefined,
});
export const createLogger = logger.child.bind(logger);

View file

@ -3,7 +3,6 @@ import { ProductUpdated, ProductUpdatedDocument } from "../../../../../generated
import { saleorApp } from "../../../../../saleor-app";
import { AlgoliaSearchProvider } from "../../../../lib/algolia/algoliaSearchProvider";
import { getAlgoliaConfiguration } from "../../../../lib/algolia/getAlgoliaConfiguration";
import { createDebug } from "../../../../lib/debug";
import { WebhookActivityTogglerService } from "../../../../domain/WebhookActivityToggler.service";
import { createClient } from "../../../../lib/graphql";
import { createLogger } from "../../../../lib/logger";

View file

@ -38,7 +38,6 @@
"jotai": "^2.0.0",
"jsdom": "^20.0.3",
"next": "13.3.0",
"pino": "^8.8.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.42.1",
@ -69,7 +68,6 @@
"eslint-config-next": "12.3.1",
"eslint-config-prettier": "^8.5.0",
"eslint-config-saleor": "workspace:*",
"pino-pretty": "^9.1.1",
"prettier": "^2.7.1",
"typescript": "4.8.4"
}

View file

@ -1,16 +1,6 @@
import pino from "pino";
import { createLogger as _createLogger, Logger } from "@saleor/apps-shared";
export const logger = pino({
level: process.env.APP_DEBUG ?? "silent",
transport:
process.env.NODE_ENV === "development"
? {
target: "pino-pretty",
options: {
colorize: true,
},
}
: undefined,
export const logger = _createLogger({
redact: [
"metadata",
"providerInstance.config.username",
@ -20,3 +10,5 @@ export const logger = pino({
});
export const createLogger = logger.child.bind(logger);
export type { Logger };

View file

@ -5,10 +5,10 @@ import {
FetchAppDetailsQuery,
UpdateMetadataDocument,
} from "../../../generated/graphql";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "../../lib/logger";
export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]> {
const logger = pinoLogger.child({ service: "fetchAllMetadata" });
const logger = createLogger({ service: "fetchAllMetadata" });
logger.debug("Fetching metadata from Saleor");
@ -27,7 +27,7 @@ export async function fetchAllMetadata(client: Client): Promise<MetadataEntry[]>
}
export async function mutateMetadata(client: Client, metadata: MetadataEntry[]) {
const logger = pinoLogger.child({ service: "mutateMetadata" });
const logger = createLogger({ service: "mutateMetadata" });
logger.debug({ metadata }, "Mutating metadata");
// to update the metadata, ID is required

View file

@ -1,6 +1,6 @@
import { NextApiResponse } from "next";
import { Logger } from "pino";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
/*
* idea: distinguish between async and sync webhooks

View file

@ -1,8 +1,7 @@
import Avatax from "avatax";
import { CreateTransactionModel } from "avatax/lib/models/CreateTransactionModel";
import pino from "pino";
import packageJson from "../../../package.json";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { AvataxConfig } from "./avatax-config";
import { CommitTransactionModel } from "avatax/lib/models/CommitTransactionModel";
import { DocumentType } from "avatax/lib/enums/DocumentType";
@ -55,7 +54,7 @@ export type ValidateAddressArgs = {
export class AvataxClient {
private client: Avatax;
private logger: pino.Logger;
private logger: Logger;
constructor(config: AvataxConfig) {
this.logger = createLogger({ service: "AvataxClient" });

View file

@ -1,5 +1,5 @@
import { z } from "zod";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "../../lib/logger";
import { isObfuscated } from "../../lib/utils";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server";
@ -33,7 +33,7 @@ const postInputSchema = z.object({
export const avataxConfigurationRouter = router({
get: protectedClientProcedure.input(getInputSchema).query(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "avataxConfigurationRouter.get",
});
@ -51,7 +51,7 @@ export const avataxConfigurationRouter = router({
return { ...result, config: obfuscateAvataxConfig(result.config) };
}),
post: protectedClientProcedure.input(postInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "avataxConfigurationRouter.post",
});
@ -68,7 +68,7 @@ export const avataxConfigurationRouter = router({
return result;
}),
delete: protectedClientProcedure.input(deleteInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "avataxConfigurationRouter.delete",
});
@ -85,7 +85,7 @@ export const avataxConfigurationRouter = router({
return result;
}),
patch: protectedClientProcedure.input(patchInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "avataxConfigurationRouter.patch",
});

View file

@ -1,6 +1,5 @@
import pino from "pino";
import { Client } from "urql";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { createSettingsManager } from "../app/metadata-manager";
import { CrudSettingsManager } from "../crud-settings/crud-settings.service";
import { providersSchema } from "../providers-configuration/providers-config";
@ -12,7 +11,7 @@ const getSchema = avataxInstanceConfigSchema;
export class AvataxConfigurationService {
private crudSettingsManager: CrudSettingsManager;
private logger: pino.Logger;
private logger: Logger;
constructor(client: Client, saleorApiUrl: string) {
const settingsManager = createSettingsManager(client);

View file

@ -1,10 +1,9 @@
import pino from "pino";
import {
OrderCreatedSubscriptionFragment,
OrderFulfilledSubscriptionFragment,
TaxBaseFragment,
} from "../../../generated/graphql";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { ChannelConfig } from "../channels-configuration/channels-config";
import { ProviderWebhookService } from "../taxes/tax-provider-webhook";
import { avataxCalculateTaxesMaps } from "./maps/avatax-calculate-taxes-map";
@ -16,7 +15,7 @@ import { avataxOrderFulfilledMaps } from "./maps/avatax-order-fulfilled-map";
export class AvataxWebhookService implements ProviderWebhookService {
config = defaultAvataxConfig;
client: AvataxClient;
private logger: pino.Logger;
private logger: Logger;
constructor(config: AvataxConfig) {
this.logger = createLogger({

View file

@ -1,4 +1,4 @@
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "../../lib/logger";
import { createSettingsManager } from "../app/metadata-manager";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server";
@ -10,7 +10,7 @@ import { GetChannelsConfigurationService } from "./get-channels-configuration.se
// todo: refactor with crud-settings
export const channelsConfigurationRouter = router({
fetch: protectedClientProcedure.query(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "channelsConfigurationRouter.fetch",
});
@ -25,7 +25,7 @@ export const channelsConfigurationRouter = router({
upsert: protectedClientProcedure
.input(setAndReplaceChannelsInputSchema)
.mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "channelsConfigurationRouter.upsert",
});

View file

@ -1,5 +1,5 @@
import { Client } from "urql";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "../../lib/logger";
import { createSettingsManager } from "../app/metadata-manager";
import { TaxChannelsConfigurator } from "./channels-configurator";
@ -12,7 +12,7 @@ export class GetChannelsConfigurationService {
) {}
async getConfiguration() {
const logger = pinoLogger.child({
const logger = createLogger({
service: "GetChannelsConfigurationService",
saleorApiUrl: this.settings.saleorApiUrl,
});

View file

@ -1,14 +1,14 @@
import { SettingsManager } from "@saleor/app-sdk/settings-manager";
import pino from "pino";
import { z } from "zod";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { createId } from "../../lib/utils";
const settingSchema = z.record(z.any()).and(z.object({ id: z.string() }));
const settingsSchema = z.array(settingSchema);
export class CrudSettingsManager {
private logger: pino.Logger;
private logger: Logger;
constructor(
private metadataManager: SettingsManager,

View file

@ -1,11 +1,11 @@
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "../../lib/logger";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server";
import { PublicTaxProvidersConfigurationService } from "./public-providers-configuration-service";
export const providersConfigurationRouter = router({
getAll: protectedClientProcedure.query(async ({ ctx }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "providersConfigurationRouter.getAll",
});

View file

@ -1,6 +1,5 @@
import pino from "pino";
import { Client } from "urql";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { obfuscateAvataxInstances } from "../avatax/avatax-config";
import { AvataxConfigurationService } from "../avatax/avatax-configuration.service";
import { obfuscateTaxJarInstances } from "../taxjar/taxjar-config";
@ -11,7 +10,7 @@ export const TAX_PROVIDER_KEY = "tax-providers";
export class PublicTaxProvidersConfigurationService {
private avataxConfigurationService: AvataxConfigurationService;
private taxJarConfigurationService: TaxJarConfigurationService;
private logger: pino.Logger;
private logger: Logger;
constructor(client: Client, saleorApiUrl: string) {
this.avataxConfigurationService = new AvataxConfigurationService(client, saleorApiUrl);
this.taxJarConfigurationService = new TaxJarConfigurationService(client, saleorApiUrl);

View file

@ -4,14 +4,14 @@ import {
OrderFulfilledSubscriptionFragment,
TaxBaseFragment,
} from "../../../generated/graphql";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { ChannelConfig } from "../channels-configuration/channels-config";
import { ProviderConfig } from "../providers-configuration/providers-config";
import { AvataxWebhookService } from "../avatax/avatax-webhook.service";
import { TaxJarWebhookService } from "../taxjar/taxjar-webhook.service";
import { ProviderWebhookService } from "./tax-provider-webhook";
import { TaxProviderError } from "./tax-provider-error";
import pino from "pino";
import { getAppConfig } from "../app/get-app-config";
type ActiveTaxProviderResult = { ok: true; data: ActiveTaxProvider } | { ok: false; error: string };
@ -63,7 +63,7 @@ export function getActiveTaxProvider(
// todo: refactor to a factory
export class ActiveTaxProvider implements ProviderWebhookService {
private client: ProviderWebhookService;
private logger: pino.Logger;
private logger: Logger;
private channel: ChannelConfig;
constructor(providerInstance: ProviderConfig, channelConfig: ChannelConfig) {

View file

@ -1,7 +1,6 @@
import pino from "pino";
import TaxJar from "taxjar";
import { AddressParams, Config, CreateOrderParams, TaxParams } from "taxjar/dist/util/types";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { TaxJarConfig } from "./taxjar-config";
const createTaxJarSettings = (config: TaxJarConfig): Config => {
@ -27,7 +26,7 @@ export type ValidateAddressArgs = {
export class TaxJarClient {
private client: TaxJar;
private logger: pino.Logger;
private logger: Logger;
constructor(providerConfig: TaxJarConfig) {
this.logger = createLogger({ service: "TaxJarClient" });

View file

@ -1,5 +1,5 @@
import { z } from "zod";
import { logger as pinoLogger } from "../../lib/logger";
import { createLogger } from "../../lib/logger";
import { isObfuscated } from "../../lib/utils";
import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server";
@ -32,7 +32,7 @@ const postInputSchema = z.object({
export const taxjarConfigurationRouter = router({
get: protectedClientProcedure.input(getInputSchema).query(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "taxjarConfigurationRouter.get",
});
@ -49,7 +49,7 @@ export const taxjarConfigurationRouter = router({
return { ...result, config: obfuscateTaxJarConfig(result.config) };
}),
post: protectedClientProcedure.input(postInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "taxjarConfigurationRouter.post",
});
@ -66,7 +66,7 @@ export const taxjarConfigurationRouter = router({
return result;
}),
delete: protectedClientProcedure.input(deleteInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "taxjarConfigurationRouter.delete",
});
@ -83,7 +83,7 @@ export const taxjarConfigurationRouter = router({
return result;
}),
patch: protectedClientProcedure.input(patchInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
const logger = createLogger({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "taxjarConfigurationRouter.patch",
});

View file

@ -1,6 +1,5 @@
import pino from "pino";
import { Client } from "urql";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { createSettingsManager } from "../app/metadata-manager";
import { CrudSettingsManager } from "../crud-settings/crud-settings.service";
import { providersSchema } from "../providers-configuration/providers-config";
@ -12,7 +11,7 @@ const getSchema = taxJarInstanceConfigSchema;
export class TaxJarConfigurationService {
private crudSettingsManager: CrudSettingsManager;
private logger: pino.Logger;
private logger: Logger;
constructor(client: Client, saleorApiUrl: string) {
const settingsManager = createSettingsManager(client);

View file

@ -1,6 +1,5 @@
import pino from "pino";
import { OrderCreatedSubscriptionFragment, TaxBaseFragment } from "../../../generated/graphql";
import { createLogger } from "../../lib/logger";
import { createLogger, Logger } from "../../lib/logger";
import { ChannelConfig } from "../channels-configuration/channels-config";
import { ProviderWebhookService } from "../taxes/tax-provider-webhook";
import { TaxJarClient } from "./taxjar-client";
@ -10,7 +9,7 @@ import { taxJarOrderCreatedMaps } from "./maps/taxjar-order-created-map";
export class TaxJarWebhookService implements ProviderWebhookService {
client: TaxJarClient;
private logger: pino.Logger;
private logger: Logger;
constructor(config: TaxJarConfig) {
const avataxClient = new TaxJarClient(config);

View file

@ -31,7 +31,7 @@
"engines": {
"node": ">=18.0.0"
},
"packageManager": "pnpm@7.29.1",
"packageManager": "pnpm@8.2.0",
"lint-staged": {
"*.{js,ts,tsx}": "eslint --cache --fix",
"*.{ts,tsx,md}": "prettier --write"

View file

@ -2,3 +2,4 @@ export * from "./src/is-in-iframe";
export * from "./src/macaw-theme-provider/macaw-theme-provider";
export * from "./src/no-ssr-wrapper";
export * from "./src/use-dashboard-notification";
export * from "./src/logger";

View file

@ -1,6 +1,10 @@
{
"name": "@saleor/apps-shared",
"version": "1.4.0",
"dependencies": {
"pino": "^8.8.0",
"pino-pretty": "^9.1.1"
},
"devDependencies": {
"@material-ui/core": "^4.12.4",
"@material-ui/icons": "^4.11.3",

Some files were not shown because too many files have changed in this diff Show more