From 9fca45c2de65b962b1b8513e617c7d569659f4d8 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Mon, 8 Apr 2024 12:23:15 +0800 Subject: [PATCH] Replace Logger with getLogger and update next version This commit replaces the use of Logger with getLogger in various parts of the code to handle logging. The Logger has been replaced with getLogger, which assists in getting logs in an asynchronous manner. In addition to this, it updates the next version in pnpm-lock.yaml from next@14.2.0-canary.61 to next@14.2.0-canary.62 and various other dependencies. Also made minor annotations and comments to the function 'isBrowser' and 'formatCurrency' in the 'utils.ts' file. --- .../_lib/server/user-billing.service.ts | 33 +++++-- .../_lib/server/team-billing.service.ts | 24 +++--- .../home/[account]/billing/return/page.tsx | 2 +- .../web/app/admin/accounts/[account]/page.tsx | 3 + apps/web/app/api/billing/webhook/route.ts | 9 +- apps/web/app/auth/callback/route.ts | 13 ++- apps/web/app/join/page.tsx | 5 +- apps/web/instrumentation.ts | 11 ++- apps/web/package.json | 2 +- .../billing-event-handler.service.ts | 37 ++++---- .../lemon-squeezy-billing-strategy.service.ts | 59 +++++++------ .../src/services/lemon-squeezy-sdk.ts | 5 +- .../lemon-squeezy-webhook-handler.service.ts | 19 ++-- .../stripe-billing-strategy.service.ts | 37 ++++---- .../stripe-webhook-handler.service.ts | 4 +- .../database-webhook-handler.service.ts | 10 ++- .../database-webhook-router.service.ts | 8 +- .../personal-accounts-server-actions.ts | 5 +- .../delete-personal-account.service.ts | 24 ++++-- .../create-team-account-server-actions.ts | 14 ++- .../account-invitations-webhook.service.ts | 43 ++++++---- .../services/account-invitations.service.ts | 30 ++++--- .../services/account-members.service.ts | 26 +++--- .../account-per-seat-billing.service.ts | 30 ++++--- .../services/create-team-account.service.ts | 10 ++- .../services/delete-team-account.service.ts | 10 ++- .../services/leave-team-account.service.ts | 10 ++- packages/mailers/README.md | 12 ++- packages/mailers/src/index.ts | 20 +---- packages/monitoring/src/instrumentation.ts | 7 +- packages/shared/src/logger/index.ts | 4 +- packages/shared/src/utils.ts | 7 ++ pnpm-lock.yaml | 86 +++++++++---------- 33 files changed, 369 insertions(+), 250 deletions(-) diff --git a/apps/web/app/(dashboard)/home/(user)/billing/_lib/server/user-billing.service.ts b/apps/web/app/(dashboard)/home/(user)/billing/_lib/server/user-billing.service.ts index 1c75e945b..df1863870 100644 --- a/apps/web/app/(dashboard)/home/(user)/billing/_lib/server/user-billing.service.ts +++ b/apps/web/app/(dashboard)/home/(user)/billing/_lib/server/user-billing.service.ts @@ -5,7 +5,7 @@ import { z } from 'zod'; import { getProductPlanPair } from '@kit/billing'; import { getBillingGatewayProvider } from '@kit/billing-gateway'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; import { requireUser } from '@kit/supabase/require-user'; import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client'; @@ -51,8 +51,9 @@ export class UserBillingService { } const { plan } = getProductPlanPair(billingConfig, planId); + const logger = await getLogger(); - Logger.info( + logger.info( { name: `billing.personal-account`, planId, @@ -73,7 +74,7 @@ export class UserBillingService { variantQuantities: [], }); - Logger.info( + logger.info( { userId: user.id, }, @@ -86,7 +87,7 @@ export class UserBillingService { checkoutToken, }; } catch (error) { - Logger.error( + logger.error( { name: `billing.personal-account`, planId, @@ -118,7 +119,9 @@ export class UserBillingService { throw new Error('Customer not found'); } - Logger.info( + const logger = await getLogger(); + + logger.info( { name: `billing.personal-account`, customerId, @@ -137,7 +140,7 @@ export class UserBillingService { url = session.url; } catch (error) { - Logger.error( + logger.error( { error, customerId, @@ -151,7 +154,7 @@ export class UserBillingService { ); } - Logger.info( + logger.info( { name: `billing.personal-account`, customerId, @@ -167,6 +170,14 @@ export class UserBillingService { async function getCustomerIdFromAccountId(accountId: string) { const client = getSupabaseServerActionClient(); + const logger = await getLogger(); + + logger.info( + { + accountId, + }, + `Getting customer ID for account ${accountId}...`, + ); const { data, error } = await client .from('billing_customers') @@ -175,6 +186,14 @@ async function getCustomerIdFromAccountId(accountId: string) { .maybeSingle(); if (error) { + logger.error( + { + accountId, + error, + }, + `Failed to get customer ID`, + ); + throw error; } diff --git a/apps/web/app/(dashboard)/home/[account]/_lib/server/team-billing.service.ts b/apps/web/app/(dashboard)/home/[account]/_lib/server/team-billing.service.ts index 1319c2950..2f950c805 100644 --- a/apps/web/app/(dashboard)/home/[account]/_lib/server/team-billing.service.ts +++ b/apps/web/app/(dashboard)/home/[account]/_lib/server/team-billing.service.ts @@ -5,7 +5,7 @@ import { z } from 'zod'; import { LineItemSchema } from '@kit/billing'; import { getBillingGatewayProvider } from '@kit/billing-gateway'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; import { requireUser } from '@kit/supabase/require-user'; import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client'; @@ -35,8 +35,9 @@ export class TeamBillingService { const userId = user.id; const accountId = params.accountId; + const logger = await getLogger(); - Logger.info( + logger.info( { userId, accountId, @@ -54,7 +55,7 @@ export class TeamBillingService { // if the user does not have permission to manage billing for the account // then we should not proceed if (!hasPermission) { - Logger.warn( + logger.warn( { userId, accountId, @@ -90,7 +91,7 @@ export class TeamBillingService { accountId, ); - Logger.info( + logger.info( { userId, accountId, @@ -117,7 +118,7 @@ export class TeamBillingService { checkoutToken, }; } catch (error) { - Logger.error( + logger.error( { name: this.namespace, error, @@ -145,8 +146,9 @@ export class TeamBillingService { slug: string; }) { const client = getSupabaseServerActionClient(); + const logger = await getLogger(); - Logger.info( + logger.info( { accountId, name: this.namespace, @@ -171,7 +173,7 @@ export class TeamBillingService { // if the user does not have permission to manage billing for the account // then we should not proceed if (!hasPermission) { - Logger.warn( + logger.warn( { userId, accountId, @@ -190,7 +192,7 @@ export class TeamBillingService { throw new Error('Customer not found'); } - Logger.info( + logger.info( { userId, customerId, @@ -211,7 +213,7 @@ export class TeamBillingService { // redirect the user to the billing portal return url; } catch (error) { - Logger.error( + logger.error( { userId, customerId, @@ -260,7 +262,9 @@ export class TeamBillingService { .eq('account_id', accountId); if (error) { - Logger.error( + const logger = await getLogger(); + + logger.error( { accountId, error, diff --git a/apps/web/app/(dashboard)/home/[account]/billing/return/page.tsx b/apps/web/app/(dashboard)/home/[account]/billing/return/page.tsx index fccface0f..617eb25a8 100644 --- a/apps/web/app/(dashboard)/home/[account]/billing/return/page.tsx +++ b/apps/web/app/(dashboard)/home/[account]/billing/return/page.tsx @@ -68,7 +68,7 @@ async function ReturnCheckoutSessionPage({ searchParams }: SessionPageProps) { export default withI18n(ReturnCheckoutSessionPage); -export async function loadCheckoutSession(sessionId: string) { +async function loadCheckoutSession(sessionId: string) { const client = getSupabaseServerComponentClient(); const { error } = await requireUser(client); diff --git a/apps/web/app/admin/accounts/[account]/page.tsx b/apps/web/app/admin/accounts/[account]/page.tsx index e69de29bb..01cd60637 100644 --- a/apps/web/app/admin/accounts/[account]/page.tsx +++ b/apps/web/app/admin/accounts/[account]/page.tsx @@ -0,0 +1,3 @@ +export default function AccountPage() { + return
; +} diff --git a/apps/web/app/api/billing/webhook/route.ts b/apps/web/app/api/billing/webhook/route.ts index 38a79abd9..0b6c97207 100644 --- a/apps/web/app/api/billing/webhook/route.ts +++ b/apps/web/app/api/billing/webhook/route.ts @@ -1,5 +1,5 @@ import { getBillingEventHandlerService } from '@kit/billing-gateway'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { getSupabaseRouteHandlerClient } from '@kit/supabase/route-handler-client'; import billingConfig from '~/config/billing.config'; @@ -9,8 +9,9 @@ import billingConfig from '~/config/billing.config'; */ export async function POST(request: Request) { const provider = billingConfig.provider; + const logger = await getLogger(); - Logger.info( + logger.info( { name: 'billing.webhook', provider, @@ -30,7 +31,7 @@ export async function POST(request: Request) { try { await service.handleWebhookEvent(request); - Logger.info( + logger.info( { name: 'billing.webhook', }, @@ -39,7 +40,7 @@ export async function POST(request: Request) { return new Response('OK', { status: 200 }); } catch (e) { - Logger.error( + logger.error( { name: 'billing', error: e, diff --git a/apps/web/app/auth/callback/route.ts b/apps/web/app/auth/callback/route.ts index 125b40e04..ac73b1b19 100644 --- a/apps/web/app/auth/callback/route.ts +++ b/apps/web/app/auth/callback/route.ts @@ -1,7 +1,7 @@ import { redirect } from 'next/navigation'; import type { NextRequest } from 'next/server'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { getSupabaseRouteHandlerClient } from '@kit/supabase/route-handler-client'; import pathsConfig from '~/config/paths.config'; @@ -38,9 +38,12 @@ export async function GET(request: NextRequest) { return onError({ error: error.message }); } } catch (error) { - Logger.error( + const logger = await getLogger(); + + logger.error( { error, + name: `auth.callback`, }, `An error occurred while exchanging code for session`, ); @@ -58,12 +61,14 @@ export async function GET(request: NextRequest) { return redirect(nextUrl); } -function onError({ error }: { error: string }) { +async function onError({ error }: { error: string }) { const errorMessage = getAuthErrorMessage(error); + const logger = await getLogger(); - Logger.error( + logger.error( { error, + name: `auth.callback`, }, `An error occurred while signing user in`, ); diff --git a/apps/web/app/join/page.tsx b/apps/web/app/join/page.tsx index 879c1071a..3aed506cb 100644 --- a/apps/web/app/join/page.tsx +++ b/apps/web/app/join/page.tsx @@ -63,9 +63,10 @@ async function JoinTeamAccountPage({ searchParams }: Context) { ); if (isInAccount) { - const { Logger } = await import('@kit/shared/logger'); + const { getLogger } = await import('@kit/shared/logger'); + const logger = await getLogger(); - Logger.warn( + logger.warn( { name: 'join-team-account', accountId: invitation.account.id, diff --git a/apps/web/instrumentation.ts b/apps/web/instrumentation.ts index ca20f6ef0..f1fd5d496 100644 --- a/apps/web/instrumentation.ts +++ b/apps/web/instrumentation.ts @@ -1,7 +1,12 @@ -import { registerInstrumentation } from '@kit/monitoring'; +/** + * This file is used to register monitoring instrumentation + * for your Next.js application. + */ +export async function register() { + // only run in nodejs runtime + if (process.env.NEXT_RUNTIME === 'nodejs') { + const { registerInstrumentation } = await import('@kit/monitoring'); -export function register() { - if (process.env.NEXT_RUNTIME !== 'nodejs') { // Register monitoring instrumentation based on the // MONITORING_INSTRUMENTATION_PROVIDER environment variable. return registerInstrumentation(); diff --git a/apps/web/package.json b/apps/web/package.json index b74214080..06178fdb1 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -45,7 +45,7 @@ "i18next": "^23.10.1", "i18next-resources-to-backend": "^1.2.0", "lucide-react": "^0.363.0", - "next": "14.2.0-canary.61", + "next": "14.2.0-canary.62", "next-sitemap": "^4.2.3", "next-themes": "0.3.0", "react": "18.2.0", diff --git a/packages/billing/gateway/src/server/services/billing-event-handler/billing-event-handler.service.ts b/packages/billing/gateway/src/server/services/billing-event-handler/billing-event-handler.service.ts index 1aad51da2..e30c07858 100644 --- a/packages/billing/gateway/src/server/services/billing-event-handler/billing-event-handler.service.ts +++ b/packages/billing/gateway/src/server/services/billing-event-handler/billing-event-handler.service.ts @@ -1,7 +1,7 @@ import { SupabaseClient } from '@supabase/supabase-js'; import { BillingWebhookHandlerService } from '@kit/billing'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; export class BillingEventHandlerService { @@ -22,10 +22,11 @@ export class BillingEventHandlerService { return this.strategy.handleWebhookEvent(event, { onSubscriptionDeleted: async (subscriptionId: string) => { const client = this.clientProvider(); + const logger = await getLogger(); // Handle the subscription deleted event // here we delete the subscription from the database - Logger.info( + logger.info( { namespace: this.namespace, subscriptionId, @@ -42,7 +43,7 @@ export class BillingEventHandlerService { throw new Error('Failed to delete subscription'); } - Logger.info( + logger.info( { namespace: this.namespace, subscriptionId, @@ -52,6 +53,7 @@ export class BillingEventHandlerService { }, onSubscriptionUpdated: async (subscription) => { const client = this.clientProvider(); + const logger = await getLogger(); const ctx = { namespace: this.namespace, @@ -61,14 +63,14 @@ export class BillingEventHandlerService { customerId: subscription.target_customer_id, }; - Logger.info(ctx, 'Processing subscription updated event'); + logger.info(ctx, 'Processing subscription updated event'); // Handle the subscription updated event // here we update the subscription in the database const { error } = await client.rpc('upsert_subscription', subscription); if (error) { - Logger.error( + logger.error( { error, ...ctx, @@ -79,12 +81,13 @@ export class BillingEventHandlerService { throw new Error('Failed to update subscription'); } - Logger.info(ctx, 'Successfully updated subscription'); + logger.info(ctx, 'Successfully updated subscription'); }, onCheckoutSessionCompleted: async (payload) => { // Handle the checkout session completed event // here we add the subscription to the database const client = this.clientProvider(); + const logger = await getLogger(); // Check if the payload contains an order_id // if it does, we add an order, otherwise we add a subscription @@ -97,17 +100,17 @@ export class BillingEventHandlerService { customerId: payload.target_customer_id, }; - Logger.info(ctx, 'Processing order completed event...'); + logger.info(ctx, 'Processing order completed event...'); const { error } = await client.rpc('upsert_order', payload); if (error) { - Logger.error({ ...ctx, error }, 'Failed to add order'); + logger.error({ ...ctx, error }, 'Failed to add order'); throw new Error('Failed to add order'); } - Logger.info(ctx, 'Successfully added order'); + logger.info(ctx, 'Successfully added order'); } else { const ctx = { namespace: this.namespace, @@ -117,25 +120,26 @@ export class BillingEventHandlerService { customerId: payload.target_customer_id, }; - Logger.info(ctx, 'Processing checkout session completed event...'); + logger.info(ctx, 'Processing checkout session completed event...'); const { error } = await client.rpc('upsert_subscription', payload); if (error) { - Logger.error({ ...ctx, error }, 'Failed to add subscription'); + logger.error({ ...ctx, error }, 'Failed to add subscription'); throw new Error('Failed to add subscription'); } - Logger.info(ctx, 'Successfully added subscription'); + logger.info(ctx, 'Successfully added subscription'); } }, onPaymentSucceeded: async (sessionId: string) => { const client = this.clientProvider(); + const logger = await getLogger(); // Handle the payment succeeded event // here we update the payment status in the database - Logger.info( + logger.info( { namespace: this.namespace, sessionId, @@ -152,7 +156,7 @@ export class BillingEventHandlerService { throw new Error('Failed to update payment status'); } - Logger.info( + logger.info( { namespace: this.namespace, sessionId, @@ -162,10 +166,11 @@ export class BillingEventHandlerService { }, onPaymentFailed: async (sessionId: string) => { const client = this.clientProvider(); + const logger = await getLogger(); // Handle the payment failed event // here we update the payment status in the database - Logger.info( + logger.info( { namespace: this.namespace, sessionId, @@ -182,7 +187,7 @@ export class BillingEventHandlerService { throw new Error('Failed to update payment status'); } - Logger.info( + logger.info( { namespace: this.namespace, sessionId, diff --git a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-billing-strategy.service.ts b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-billing-strategy.service.ts index 95a98e939..019f840f5 100644 --- a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-billing-strategy.service.ts +++ b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-billing-strategy.service.ts @@ -16,7 +16,7 @@ import { RetrieveCheckoutSessionSchema, UpdateSubscriptionParamsSchema, } from '@kit/billing/schema'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { createLemonSqueezyBillingPortalSession } from './create-lemon-squeezy-billing-portal-session'; import { createLemonSqueezyCheckout } from './create-lemon-squeezy-checkout'; @@ -27,13 +27,12 @@ export class LemonSqueezyBillingStrategyService async createCheckoutSession( params: z.infer, ) { - Logger.info( + const logger = await getLogger(); + + logger.info( { name: 'billing.lemon-squeezy', - customerId: params.customerId, - accountId: params.accountId, - returnUrl: params.returnUrl, - trialDays: params.trialDays, + ...params, }, 'Creating checkout session...', ); @@ -43,7 +42,7 @@ export class LemonSqueezyBillingStrategyService if (error ?? !response?.data.id) { console.log(error); - Logger.error( + logger.error( { name: 'billing.lemon-squeezy', customerId: params.customerId, @@ -56,7 +55,7 @@ export class LemonSqueezyBillingStrategyService throw new Error('Failed to create checkout session'); } - Logger.info( + logger.info( { name: 'billing.lemon-squeezy', customerId: params.customerId, @@ -73,7 +72,9 @@ export class LemonSqueezyBillingStrategyService async createBillingPortalSession( params: z.infer, ) { - Logger.info( + const logger = await getLogger(); + + logger.info( { name: 'billing.lemon-squeezy', customerId: params.customerId, @@ -85,7 +86,7 @@ export class LemonSqueezyBillingStrategyService await createLemonSqueezyBillingPortalSession(params); if (error ?? !data) { - Logger.error( + logger.error( { name: 'billing.lemon-squeezy', customerId: params.customerId, @@ -97,7 +98,7 @@ export class LemonSqueezyBillingStrategyService throw new Error('Failed to create billing portal session'); } - Logger.info( + logger.info( { name: 'billing.lemon-squeezy', customerId: params.customerId, @@ -111,7 +112,9 @@ export class LemonSqueezyBillingStrategyService async cancelSubscription( params: z.infer, ) { - Logger.info( + const logger = await getLogger(); + + logger.info( { name: 'billing.lemon-squeezy', subscriptionId: params.subscriptionId, @@ -123,7 +126,7 @@ export class LemonSqueezyBillingStrategyService const { error } = await cancelSubscription(params.subscriptionId); if (error) { - Logger.error( + logger.error( { name: 'billing.lemon-squeezy', subscriptionId: params.subscriptionId, @@ -135,7 +138,7 @@ export class LemonSqueezyBillingStrategyService throw error; } - Logger.info( + logger.info( { name: 'billing.lemon-squeezy', subscriptionId: params.subscriptionId, @@ -145,7 +148,7 @@ export class LemonSqueezyBillingStrategyService return { success: true }; } catch (error) { - Logger.error( + logger.error( { name: 'billing.lemon-squeezy', subscriptionId: params.subscriptionId, @@ -161,7 +164,9 @@ export class LemonSqueezyBillingStrategyService async retrieveCheckoutSession( params: z.infer, ) { - Logger.info( + const logger = await getLogger(); + + logger.info( { name: 'billing.lemon-squeezy', sessionId: params.sessionId, @@ -172,7 +177,7 @@ export class LemonSqueezyBillingStrategyService const { data: session, error } = await getCheckout(params.sessionId); if (error ?? !session?.data) { - Logger.error( + logger.error( { name: 'billing.lemon-squeezy', sessionId: params.sessionId, @@ -184,7 +189,7 @@ export class LemonSqueezyBillingStrategyService throw new Error('Failed to retrieve checkout session'); } - Logger.info( + logger.info( { name: 'billing.lemon-squeezy', sessionId: params.sessionId, @@ -205,7 +210,9 @@ export class LemonSqueezyBillingStrategyService } async reportUsage(params: z.infer) { - Logger.info( + const logger = await getLogger(); + + logger.info( { name: 'billing.lemon-squeezy', subscriptionItemId: params.subscriptionItemId, @@ -220,11 +227,11 @@ export class LemonSqueezyBillingStrategyService }); if (error) { - Logger.error( + logger.error( { name: 'billing.lemon-squeezy', subscriptionItemId: params.subscriptionItemId, - error: error.message, + error, }, 'Failed to report usage', ); @@ -232,7 +239,7 @@ export class LemonSqueezyBillingStrategyService throw new Error('Failed to report usage'); } - Logger.info( + logger.info( { name: 'billing.lemon-squeezy', subscriptionItemId: params.subscriptionItemId, @@ -246,19 +253,21 @@ export class LemonSqueezyBillingStrategyService async updateSubscription( params: z.infer, ) { + const logger = await getLogger(); + const ctx = { name: 'billing.lemon-squeezy', ...params, }; - Logger.info(ctx, 'Updating subscription...'); + logger.info(ctx, 'Updating subscription...'); const { error } = await updateSubscriptionItem(params.subscriptionItemId, { quantity: params.quantity, }); if (error) { - Logger.error( + logger.error( { ...ctx, error, @@ -269,7 +278,7 @@ export class LemonSqueezyBillingStrategyService throw error; } - Logger.info(ctx, 'Subscription updated successfully'); + logger.info(ctx, 'Subscription updated successfully'); return { success: true }; } diff --git a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-sdk.ts b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-sdk.ts index ced371d5e..5ed20968e 100644 --- a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-sdk.ts +++ b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-sdk.ts @@ -1,6 +1,6 @@ import 'server-only'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { getLemonSqueezyEnv } from '../schema/lemon-squeezy-server-env.schema'; @@ -10,11 +10,12 @@ import { getLemonSqueezyEnv } from '../schema/lemon-squeezy-server-env.schema'; export async function initializeLemonSqueezyClient() { const { lemonSqueezySetup } = await import('@lemonsqueezy/lemonsqueezy.js'); const env = getLemonSqueezyEnv(); + const logger = await getLogger(); lemonSqueezySetup({ apiKey: env.secretKey, onError(error) { - Logger.error( + logger.error( { name: `billing.lemon-squeezy`, error: error.message, diff --git a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts index addf7b8d5..113831ea9 100644 --- a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts +++ b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts @@ -6,7 +6,7 @@ import { BillingWebhookHandlerService, getLineItemTypeById, } from '@kit/billing'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; import { getLemonSqueezyEnv } from '../schema/lemon-squeezy-server-env.schema'; @@ -45,6 +45,9 @@ export class LemonSqueezyWebhookHandlerService * @description Verifies the webhook signature - should throw an error if the signature is invalid */ async verifyWebhookSignature(request: Request) { + const logger = await getLogger(); + + // get the event name and signature from the headers const eventName = request.headers.get('x-event-name'); const signature = request.headers.get('x-signature') as string; @@ -53,8 +56,9 @@ export class LemonSqueezyWebhookHandlerService const body = (await request.json()) as SubscriptionWebhook | OrderWebhook; const rawBody = await reqClone.text(); + // if no signature is found, throw an error if (!signature) { - Logger.error( + logger.error( { eventName, }, @@ -64,8 +68,9 @@ export class LemonSqueezyWebhookHandlerService throw new Error('Signature header not found'); } + // if the signature is invalid, throw an error if (!isSigningSecretValid(Buffer.from(rawBody), signature)) { - Logger.error( + logger.error( { eventName, }, @@ -124,7 +129,9 @@ export class LemonSqueezyWebhookHandlerService } default: { - Logger.info( + const logger = await getLogger(); + + logger.info( { eventType: eventName, name: this.namespace, @@ -211,7 +218,9 @@ export class LemonSqueezyWebhookHandlerService const { data: order, error } = await getOrder(orderId); if (error ?? !order) { - Logger.error( + const logger = await getLogger(); + + logger.error( { orderId, subscriptionId, diff --git a/packages/billing/stripe/src/services/stripe-billing-strategy.service.ts b/packages/billing/stripe/src/services/stripe-billing-strategy.service.ts index 1e49ff72f..264571706 100644 --- a/packages/billing/stripe/src/services/stripe-billing-strategy.service.ts +++ b/packages/billing/stripe/src/services/stripe-billing-strategy.service.ts @@ -11,7 +11,7 @@ import { RetrieveCheckoutSessionSchema, UpdateSubscriptionParamsSchema, } from '@kit/billing/schema'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { createStripeBillingPortalSession } from './create-stripe-billing-portal-session'; import { createStripeCheckout } from './create-stripe-checkout'; @@ -24,8 +24,9 @@ export class StripeBillingStrategyService params: z.infer, ) { const stripe = await this.stripeProvider(); + const logger = await getLogger(); - Logger.info( + logger.info( { name: 'billing.stripe', customerId: params.customerId, @@ -37,7 +38,7 @@ export class StripeBillingStrategyService const { client_secret } = await createStripeCheckout(stripe, params); if (!client_secret) { - Logger.error( + logger.error( { name: 'billing.stripe', customerId: params.customerId, @@ -49,7 +50,7 @@ export class StripeBillingStrategyService throw new Error('Failed to create checkout session'); } - Logger.info( + logger.info( { name: 'billing.stripe', customerId: params.customerId, @@ -65,8 +66,9 @@ export class StripeBillingStrategyService params: z.infer, ) { const stripe = await this.stripeProvider(); + const logger = await getLogger(); - Logger.info( + logger.info( { name: 'billing.stripe', customerId: params.customerId, @@ -77,7 +79,7 @@ export class StripeBillingStrategyService const session = await createStripeBillingPortalSession(stripe, params); if (!session?.url) { - Logger.error( + logger.error( { name: 'billing.stripe', customerId: params.customerId, @@ -85,7 +87,7 @@ export class StripeBillingStrategyService 'Failed to create billing portal session', ); } else { - Logger.info( + logger.info( { name: 'billing.stripe', customerId: params.customerId, @@ -101,8 +103,9 @@ export class StripeBillingStrategyService params: z.infer, ) { const stripe = await this.stripeProvider(); + const logger = await getLogger(); - Logger.info( + logger.info( { name: 'billing.stripe', subscriptionId: params.subscriptionId, @@ -115,7 +118,7 @@ export class StripeBillingStrategyService invoice_now: params.invoiceNow ?? true, }); - Logger.info( + logger.info( { name: 'billing.stripe', subscriptionId: params.subscriptionId, @@ -125,7 +128,7 @@ export class StripeBillingStrategyService return { success: true }; } catch (e) { - Logger.error( + logger.error( { name: 'billing.stripe', subscriptionId: params.subscriptionId, @@ -142,8 +145,9 @@ export class StripeBillingStrategyService params: z.infer, ) { const stripe = await this.stripeProvider(); + const logger = await getLogger(); - Logger.info( + logger.info( { name: 'billing.stripe', sessionId: params.sessionId, @@ -155,7 +159,7 @@ export class StripeBillingStrategyService const session = await stripe.checkout.sessions.retrieve(params.sessionId); const isSessionOpen = session.status === 'open'; - Logger.info( + logger.info( { name: 'billing.stripe', sessionId: params.sessionId, @@ -172,7 +176,7 @@ export class StripeBillingStrategyService }, }; } catch (error) { - Logger.error( + logger.error( { name: 'billing.stripe', sessionId: params.sessionId, @@ -203,8 +207,9 @@ export class StripeBillingStrategyService params: z.infer, ) { const stripe = await this.stripeProvider(); + const logger = await getLogger(); - Logger.info( + logger.info( { name: 'billing.stripe', ...params, @@ -222,7 +227,7 @@ export class StripeBillingStrategyService ], }); - Logger.info( + logger.info( { name: 'billing.stripe', ...params, @@ -232,7 +237,7 @@ export class StripeBillingStrategyService return { success: true }; } catch (e) { - Logger.error( + logger.error( { name: 'billing.stripe', ...params, diff --git a/packages/billing/stripe/src/services/stripe-webhook-handler.service.ts b/packages/billing/stripe/src/services/stripe-webhook-handler.service.ts index 2e827c8ac..97d632341 100644 --- a/packages/billing/stripe/src/services/stripe-webhook-handler.service.ts +++ b/packages/billing/stripe/src/services/stripe-webhook-handler.service.ts @@ -5,7 +5,7 @@ import { BillingWebhookHandlerService, getLineItemTypeById, } from '@kit/billing'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; import { StripeServerEnvSchema } from '../schema/stripe-server-env.schema'; @@ -113,6 +113,8 @@ export class StripeWebhookHandlerService } default: { + const Logger = await getLogger(); + Logger.info( { eventType: event.type, diff --git a/packages/database-webhooks/src/server/services/database-webhook-handler.service.ts b/packages/database-webhooks/src/server/services/database-webhook-handler.service.ts index 6ca8ea259..7dc104199 100644 --- a/packages/database-webhooks/src/server/services/database-webhook-handler.service.ts +++ b/packages/database-webhooks/src/server/services/database-webhook-handler.service.ts @@ -1,6 +1,6 @@ import 'server-only'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { getSupabaseRouteHandlerClient } from '@kit/supabase/route-handler-client'; import { RecordChange, Tables } from '../record-change.type'; @@ -10,10 +10,12 @@ export class DatabaseWebhookHandlerService { private readonly namespace = 'database-webhook-handler'; async handleWebhook(request: Request, webhooksSecret: string) { + const logger = await getLogger(); + const json = await request.clone().json(); const { table, type } = json as RecordChange; - Logger.info( + logger.info( { name: this.namespace, table, @@ -40,7 +42,7 @@ export class DatabaseWebhookHandlerService { // handle the webhook event based on the table await service.handleWebhook(json); - Logger.info( + logger.info( { name: this.namespace, table, @@ -49,7 +51,7 @@ export class DatabaseWebhookHandlerService { 'Webhook processed successfully', ); } catch (error) { - Logger.error( + logger.error( { name: this.namespace, table, diff --git a/packages/database-webhooks/src/server/services/database-webhook-router.service.ts b/packages/database-webhooks/src/server/services/database-webhook-router.service.ts index 47b2885d4..66c8e7be5 100644 --- a/packages/database-webhooks/src/server/services/database-webhook-router.service.ts +++ b/packages/database-webhooks/src/server/services/database-webhook-router.service.ts @@ -1,6 +1,6 @@ import { SupabaseClient } from '@supabase/supabase-js'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; import { RecordChange, Tables } from '../record-change.type'; @@ -8,7 +8,7 @@ import { RecordChange, Tables } from '../record-change.type'; export class DatabaseWebhookRouterService { constructor(private readonly adminClient: SupabaseClient) {} - handleWebhook(body: RecordChange) { + async handleWebhook(body: RecordChange) { switch (body.table) { case 'invitations': { const payload = body as RecordChange; @@ -23,7 +23,9 @@ export class DatabaseWebhookRouterService { } default: { - Logger.warn( + const logger = await getLogger(); + + logger.warn( { table: body.table, }, diff --git a/packages/features/accounts/src/server/personal-accounts-server-actions.ts b/packages/features/accounts/src/server/personal-accounts-server-actions.ts index f63a62b27..ea4c116ee 100644 --- a/packages/features/accounts/src/server/personal-accounts-server-actions.ts +++ b/packages/features/accounts/src/server/personal-accounts-server-actions.ts @@ -4,7 +4,7 @@ import { RedirectType, redirect } from 'next/navigation'; import { z } from 'zod'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { requireUser } from '@kit/supabase/require-user'; import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client'; @@ -31,7 +31,8 @@ export async function deletePersonalAccountAction(formData: FormData) { const auth = await requireUser(client); if (auth.error) { - Logger.error(`User is not authenticated. Redirecting to login page`); + const logger = await getLogger(); + logger.error(`User is not authenticated. Redirecting to login page`); redirect(auth.redirectTo); } diff --git a/packages/features/accounts/src/server/services/delete-personal-account.service.ts b/packages/features/accounts/src/server/services/delete-personal-account.service.ts index 7d2baa01b..af0ad02e3 100644 --- a/packages/features/accounts/src/server/services/delete-personal-account.service.ts +++ b/packages/features/accounts/src/server/services/delete-personal-account.service.ts @@ -1,7 +1,6 @@ import { SupabaseClient } from '@supabase/supabase-js'; -import { Mailer } from '@kit/mailers'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; /** @@ -35,8 +34,9 @@ export class DeletePersonalAccountService { }; }) { const userId = params.userId; + const logger = await getLogger(); - Logger.info( + logger.info( { name: this.namespace, userId }, 'User requested deletion. Processing...', ); @@ -45,7 +45,7 @@ export class DeletePersonalAccountService { try { await params.adminClient.auth.admin.deleteUser(userId); } catch (error) { - Logger.error( + logger.error( { name: this.namespace, userId, @@ -60,7 +60,7 @@ export class DeletePersonalAccountService { // Send account deletion email if (params.userEmail) { try { - Logger.info( + logger.info( { name: this.namespace, userId, @@ -74,8 +74,16 @@ export class DeletePersonalAccountService { userDisplayName: params.userEmail, userEmail: params.userEmail, }); + + logger.info( + { + name: this.namespace, + userId, + }, + `Account deletion email sent`, + ); } catch (error) { - Logger.error( + logger.error( { name: this.namespace, userId, @@ -94,13 +102,15 @@ export class DeletePersonalAccountService { productName: string; }) { const { renderAccountDeleteEmail } = await import('@kit/email-templates'); + const { getMailer } = await import('@kit/mailers'); + const mailer = await getMailer(); const html = renderAccountDeleteEmail({ userDisplayName: params.userDisplayName, productName: params.productName, }); - await Mailer.sendEmail({ + return mailer.sendEmail({ to: params.userEmail, from: params.fromEmail, subject: 'Account Deletion Request', diff --git a/packages/features/team-accounts/src/server/actions/create-team-account-server-actions.ts b/packages/features/team-accounts/src/server/actions/create-team-account-server-actions.ts index bd7e5307e..c75f65c8d 100644 --- a/packages/features/team-accounts/src/server/actions/create-team-account-server-actions.ts +++ b/packages/features/team-accounts/src/server/actions/create-team-account-server-actions.ts @@ -4,7 +4,7 @@ import { redirect } from 'next/navigation'; import { z } from 'zod'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { requireUser } from '@kit/supabase/require-user'; import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client'; @@ -31,6 +31,7 @@ export async function createOrganizationAccountAction( redirect(auth.redirectTo); } + const logger = await getLogger(); const userId = auth.data.id; const createAccountResponse = await service.createNewOrganizationAccount({ @@ -39,7 +40,7 @@ export async function createOrganizationAccountAction( }); if (createAccountResponse.error) { - Logger.error( + logger.error( { userId, error: createAccountResponse.error, @@ -51,6 +52,15 @@ export async function createOrganizationAccountAction( throw new Error('Error creating team account'); } + logger.info( + { + userId, + accountName, + name: 'accounts', + }, + `Team account created successfully`, + ); + const accountHomePath = TEAM_ACCOUNTS_HOME_PATH + '/' + createAccountResponse.data.slug; diff --git a/packages/features/team-accounts/src/server/services/account-invitations-webhook.service.ts b/packages/features/team-accounts/src/server/services/account-invitations-webhook.service.ts index 4b0e14ada..c8e6c9cb9 100644 --- a/packages/features/team-accounts/src/server/services/account-invitations-webhook.service.ts +++ b/packages/features/team-accounts/src/server/services/account-invitations-webhook.service.ts @@ -2,8 +2,7 @@ import { SupabaseClient } from '@supabase/supabase-js'; import { z } from 'zod'; -import { Mailer } from '@kit/mailers'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; type Invitation = Database['public']['Tables']['invitations']['Row']; @@ -57,8 +56,12 @@ export class AccountInvitationsWebhookService { throw team.error; } + const logger = await getLogger(); + try { const { renderInviteEmail } = await import('@kit/email-templates'); + const { getMailer } = await import('@kit/mailers'); + const mailer = await getMailer(); const html = renderInviteEmail({ link: this.getInvitationLink(invitation.invite_token), @@ -68,26 +71,34 @@ export class AccountInvitationsWebhookService { teamName: team.data.name, }); - await Mailer.sendEmail({ - from: env.emailSender, - to: invitation.email, - subject: 'You have been invited to join a team', - html, - }); - - Logger.info('Invitation email sent', { - email: invitation.email, - account: invitation.account_id, - name: this.namespace, - }); + await mailer + .sendEmail({ + from: env.emailSender, + to: invitation.email, + subject: 'You have been invited to join a team', + html, + }) + .then(() => { + logger.info('Invitation email sent', { + email: invitation.email, + account: invitation.account_id, + name: this.namespace, + }); + }) + .catch((error) => { + logger.warn( + { error, name: this.namespace }, + 'Failed to send invitation email', + ); + }); return { success: true, }; } catch (error) { - Logger.warn( + logger.warn( { error, name: this.namespace }, - 'Failed to send invitation email', + 'Failed to invite user to team', ); return { diff --git a/packages/features/team-accounts/src/server/services/account-invitations.service.ts b/packages/features/team-accounts/src/server/services/account-invitations.service.ts index 3762aea42..e21bb874e 100644 --- a/packages/features/team-accounts/src/server/services/account-invitations.service.ts +++ b/packages/features/team-accounts/src/server/services/account-invitations.service.ts @@ -4,7 +4,7 @@ import { addDays, formatISO } from 'date-fns'; import 'server-only'; import { z } from 'zod'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; import { DeleteInvitationSchema } from '../../schema/delete-invitation.schema'; @@ -17,7 +17,9 @@ export class AccountInvitationsService { constructor(private readonly client: SupabaseClient) {} async deleteInvitation(params: z.infer) { - Logger.info('Removing invitation', { + const logger = await getLogger(); + + logger.info('Removing invitation', { name: this.namespace, ...params, }); @@ -33,7 +35,7 @@ export class AccountInvitationsService { throw error; } - Logger.info('Invitation successfully removed', { + logger.info('Invitation successfully removed', { ...params, name: this.namespace, }); @@ -42,7 +44,9 @@ export class AccountInvitationsService { } async updateInvitation(params: z.infer) { - Logger.info('Updating invitation', { + const logger = await getLogger(); + + logger.info('Updating invitation', { ...params, name: this.namespace, }); @@ -60,7 +64,7 @@ export class AccountInvitationsService { throw error; } - Logger.info('Invitation successfully updated', { + logger.info('Invitation successfully updated', { ...params, name: this.namespace, }); @@ -75,7 +79,9 @@ export class AccountInvitationsService { invitations: z.infer['invitations']; accountSlug: string; }) { - Logger.info( + const logger = await getLogger(); + + logger.info( { account: accountSlug, invitations, @@ -91,7 +97,7 @@ export class AccountInvitationsService { .single(); if (!accountResponse.data) { - Logger.error( + logger.error( { accountSlug, name: this.namespace, @@ -108,7 +114,7 @@ export class AccountInvitationsService { }); if (response.error) { - Logger.error( + logger.error( { accountSlug, error: response.error, @@ -124,7 +130,7 @@ export class AccountInvitationsService { ? response.data : [response.data]; - Logger.info( + logger.info( { account: accountSlug, count: responseInvitations.length, @@ -157,7 +163,9 @@ export class AccountInvitationsService { } async renewInvitation(invitationId: number) { - Logger.info('Renewing invitation', { + const logger = await getLogger(); + + logger.info('Renewing invitation', { invitationId, name: this.namespace, }); @@ -177,7 +185,7 @@ export class AccountInvitationsService { throw error; } - Logger.info('Invitation successfully renewed', { + logger.info('Invitation successfully renewed', { invitationId, name: this.namespace, }); diff --git a/packages/features/team-accounts/src/server/services/account-members.service.ts b/packages/features/team-accounts/src/server/services/account-members.service.ts index 1867fcf96..5f7e895eb 100644 --- a/packages/features/team-accounts/src/server/services/account-members.service.ts +++ b/packages/features/team-accounts/src/server/services/account-members.service.ts @@ -3,7 +3,7 @@ import { SupabaseClient } from '@supabase/supabase-js'; import 'server-only'; import { z } from 'zod'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; import { RemoveMemberSchema } from '../../schema/remove-member.schema'; @@ -17,12 +17,14 @@ export class AccountMembersService { constructor(private readonly client: SupabaseClient) {} async removeMemberFromAccount(params: z.infer) { + const logger = await getLogger(); + const ctx = { namespace: this.namespace, ...params, }; - Logger.info(ctx, `Removing member from account...`); + logger.info(ctx, `Removing member from account...`); const { data, error } = await this.client .from('accounts_memberships') @@ -33,7 +35,7 @@ export class AccountMembersService { }); if (error) { - Logger.error( + logger.error( { ...ctx, error, @@ -44,7 +46,7 @@ export class AccountMembersService { throw error; } - Logger.info( + logger.info( ctx, `Successfully removed member from account. Verifying seat count...`, ); @@ -57,12 +59,14 @@ export class AccountMembersService { } async updateMemberRole(params: z.infer) { + const logger = await getLogger(); + const ctx = { namespace: this.namespace, ...params, }; - Logger.info(ctx, `Updating member role...`); + logger.info(ctx, `Updating member role...`); const { data, error } = await this.client .from('accounts_memberships') @@ -75,7 +79,7 @@ export class AccountMembersService { }); if (error) { - Logger.error( + logger.error( { ...ctx, error, @@ -86,7 +90,7 @@ export class AccountMembersService { throw error; } - Logger.info(ctx, `Successfully updated member role`); + logger.info(ctx, `Successfully updated member role`); return data; } @@ -94,12 +98,14 @@ export class AccountMembersService { async transferOwnership( params: z.infer, ) { + const logger = await getLogger(); + const ctx = { namespace: this.namespace, ...params, }; - Logger.info(ctx, `Transferring ownership of account...`); + logger.info(ctx, `Transferring ownership of account...`); const { data, error } = await this.client.rpc( 'transfer_team_account_ownership', @@ -110,7 +116,7 @@ export class AccountMembersService { ); if (error) { - Logger.error( + logger.error( { ...ctx, error }, `Failed to transfer ownership of account`, ); @@ -118,7 +124,7 @@ export class AccountMembersService { throw error; } - Logger.info(ctx, `Successfully transferred ownership of account`); + logger.info(ctx, `Successfully transferred ownership of account`); return data; } diff --git a/packages/features/team-accounts/src/server/services/account-per-seat-billing.service.ts b/packages/features/team-accounts/src/server/services/account-per-seat-billing.service.ts index 465dc993c..d1ba73b08 100644 --- a/packages/features/team-accounts/src/server/services/account-per-seat-billing.service.ts +++ b/packages/features/team-accounts/src/server/services/account-per-seat-billing.service.ts @@ -1,7 +1,7 @@ import { SupabaseClient } from '@supabase/supabase-js'; import { BillingGatewayService } from '@kit/billing-gateway'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; export class AccountPerSeatBillingService { @@ -10,7 +10,9 @@ export class AccountPerSeatBillingService { constructor(private readonly client: SupabaseClient) {} async getPerSeatSubscriptionItem(accountId: string) { - Logger.info( + const logger = await getLogger(); + + logger.info( { name: this.namespace, accountId, @@ -36,7 +38,7 @@ export class AccountPerSeatBillingService { .maybeSingle(); if (error) { - Logger.info( + logger.error( { name: this.namespace, accountId, @@ -49,7 +51,7 @@ export class AccountPerSeatBillingService { } if (!data?.subscription_items) { - Logger.info( + logger.info( { name: this.namespace, accountId }, `No per-seat subscription item found for account ${accountId}. Exiting...`, ); @@ -57,7 +59,7 @@ export class AccountPerSeatBillingService { return; } - Logger.info( + logger.info( { name: this.namespace, accountId, @@ -69,6 +71,7 @@ export class AccountPerSeatBillingService { } async increaseSeats(accountId: string) { + const logger = await getLogger(); const subscription = await this.getPerSeatSubscriptionItem(accountId); if (!subscription) { @@ -85,7 +88,7 @@ export class AccountPerSeatBillingService { const billingGateway = new BillingGatewayService(subscription.provider); - Logger.info( + logger.info( { name: this.namespace, accountId, @@ -96,7 +99,7 @@ export class AccountPerSeatBillingService { const promises = subscriptionItems.map(async (item) => { try { - Logger.info( + logger.info( { name: this.namespace, accountId, @@ -112,7 +115,7 @@ export class AccountPerSeatBillingService { quantity: item.quantity + 1, }); - Logger.info( + logger.info( { name: this.namespace, accountId, @@ -122,7 +125,7 @@ export class AccountPerSeatBillingService { `Subscription item updated successfully`, ); } catch (error) { - Logger.error( + logger.error( { name: this.namespace, accountId, @@ -137,6 +140,7 @@ export class AccountPerSeatBillingService { } async decreaseSeats(accountId: string) { + const logger = await getLogger(); const subscription = await this.getPerSeatSubscriptionItem(accountId); if (!subscription) { @@ -151,7 +155,7 @@ export class AccountPerSeatBillingService { return; } - Logger.info( + logger.info( { name: this.namespace, accountId, @@ -164,7 +168,7 @@ export class AccountPerSeatBillingService { const promises = subscriptionItems.map(async (item) => { try { - Logger.info( + logger.info( { name: this.namespace, accountId, @@ -180,7 +184,7 @@ export class AccountPerSeatBillingService { quantity: item.quantity - 1, }); - Logger.info( + logger.info( { name: this.namespace, accountId, @@ -190,7 +194,7 @@ export class AccountPerSeatBillingService { `Subscription item updated successfully`, ); } catch (error) { - Logger.error( + logger.error( { name: this.namespace, accountId, diff --git a/packages/features/team-accounts/src/server/services/create-team-account.service.ts b/packages/features/team-accounts/src/server/services/create-team-account.service.ts index e69f0d9f2..596364981 100644 --- a/packages/features/team-accounts/src/server/services/create-team-account.service.ts +++ b/packages/features/team-accounts/src/server/services/create-team-account.service.ts @@ -1,6 +1,6 @@ import { SupabaseClient } from '@supabase/supabase-js'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; export class CreateTeamAccountService { @@ -8,13 +8,15 @@ export class CreateTeamAccountService { constructor(private readonly client: SupabaseClient) {} - createNewOrganizationAccount(params: { name: string; userId: string }) { - Logger.info( + async createNewOrganizationAccount(params: { name: string; userId: string }) { + const logger = await getLogger(); + + logger.info( { ...params, namespace: this.namespace }, `Creating new team account...`, ); - return this.client.rpc('create_account', { + return await this.client.rpc('create_account', { account_name: params.name, }); } diff --git a/packages/features/team-accounts/src/server/services/delete-team-account.service.ts b/packages/features/team-accounts/src/server/services/delete-team-account.service.ts index bf527c447..95bd612b8 100644 --- a/packages/features/team-accounts/src/server/services/delete-team-account.service.ts +++ b/packages/features/team-accounts/src/server/services/delete-team-account.service.ts @@ -2,7 +2,7 @@ import { SupabaseClient } from '@supabase/supabase-js'; import 'server-only'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; export class DeleteTeamAccountService { @@ -24,7 +24,9 @@ export class DeleteTeamAccountService { userId: string; }, ) { - Logger.info( + const logger = await getLogger(); + + logger.info( { name: this.namespace, accountId: params.accountId, @@ -40,7 +42,7 @@ export class DeleteTeamAccountService { .eq('id', params.accountId); if (error) { - Logger.error( + logger.error( { name: this.namespace, accountId: params.accountId, @@ -53,7 +55,7 @@ export class DeleteTeamAccountService { throw new Error('Failed to delete team account'); } - Logger.info( + logger.info( { name: this.namespace, accountId: params.accountId, diff --git a/packages/features/team-accounts/src/server/services/leave-team-account.service.ts b/packages/features/team-accounts/src/server/services/leave-team-account.service.ts index a889eb68a..dd7ae45af 100644 --- a/packages/features/team-accounts/src/server/services/leave-team-account.service.ts +++ b/packages/features/team-accounts/src/server/services/leave-team-account.service.ts @@ -3,7 +3,7 @@ import { SupabaseClient } from '@supabase/supabase-js'; import 'server-only'; import { z } from 'zod'; -import { Logger } from '@kit/shared/logger'; +import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; const Schema = z.object({ @@ -17,12 +17,14 @@ export class LeaveTeamAccountService { constructor(private readonly adminClient: SupabaseClient) {} async leaveTeamAccount(params: z.infer) { + const logger = await getLogger(); + const ctx = { ...params, name: this.namespace, }; - Logger.info(ctx, 'Leaving team account'); + logger.info(ctx, 'Leaving team account...'); const { accountId, userId } = Schema.parse(params); @@ -35,11 +37,11 @@ export class LeaveTeamAccountService { }); if (error) { - Logger.error({ ...ctx, error }, 'Failed to leave team account'); + logger.error({ ...ctx, error }, 'Failed to leave team account'); throw new Error('Failed to leave team account'); } - Logger.info(ctx, 'Successfully left team account'); + logger.info(ctx, 'Successfully left team account'); } } diff --git a/packages/mailers/README.md b/packages/mailers/README.md index 8e72fe613..aef5e5fc8 100644 --- a/packages/mailers/README.md +++ b/packages/mailers/README.md @@ -27,13 +27,17 @@ MAILER_PROVIDER=cloudflare ### Send an email -```javascript -import { Mailer } from '@kit/mailers'; +```tsx +import { getMailer } from '@kit/mailers'; -Mailer.sendEmail({ +async function sendEmail() { + const mailer = await getMailer(); + + return mailer.sendEmail({ to: '', from: '', subject: 'Hello', text: 'Hello, World!' -}); + }); +} ``` \ No newline at end of file diff --git a/packages/mailers/src/index.ts b/packages/mailers/src/index.ts index 51f4af572..349cef6a5 100644 --- a/packages/mailers/src/index.ts +++ b/packages/mailers/src/index.ts @@ -5,28 +5,10 @@ const MAILER_PROVIDER = z .default('nodemailer') .parse(process.env.MAILER_PROVIDER); -/** - * @description A mailer interface that can be implemented by any mailer. - * We export a single mailer implementation using Nodemailer. You can add more mailers or replace the existing one. - * @example - * ```ts - * import { Mailer } from '@kit/mailers'; - * - * const mailer = new Mailer(); - * - * mailer.sendEmail({ - * from: '', - * to: '', - * subject: 'Hello', - * text: 'Hello, World!' - * }); - */ -export const Mailer = await getMailer(); - /** * @description Get the mailer based on the environment variable. */ -async function getMailer() { +export async function getMailer() { switch (MAILER_PROVIDER) { case 'nodemailer': { const { Nodemailer } = await import('./impl/nodemailer'); diff --git a/packages/monitoring/src/instrumentation.ts b/packages/monitoring/src/instrumentation.ts index 70e228ac4..8feeb5602 100644 --- a/packages/monitoring/src/instrumentation.ts +++ b/packages/monitoring/src/instrumentation.ts @@ -17,10 +17,9 @@ const DEFAULT_INSTRUMENTATION_PROVIDER = process.env * Please set the MONITORING_INSTRUMENTATION_PROVIDER environment variable to register the monitoring instrumentation provider. */ export async function registerInstrumentation() { - if ( - process.env.NEXT_RUNTIME !== 'nodejs' || - !DEFAULT_INSTRUMENTATION_PROVIDER - ) { + if (!DEFAULT_INSTRUMENTATION_PROVIDER) { + console.info(`No instrumentation provider specified. Skipping...`); + return; } diff --git a/packages/shared/src/logger/index.ts b/packages/shared/src/logger/index.ts index e6610e16b..c21d244dc 100644 --- a/packages/shared/src/logger/index.ts +++ b/packages/shared/src/logger/index.ts @@ -20,6 +20,4 @@ async function getLogger(): Promise { } } -const Logger = await getLogger(); - -export { Logger }; +export { getLogger }; diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index f440452f7..a17807e98 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -1,7 +1,14 @@ +/** + * Check if the code is running in a browser environment. + */ export function isBrowser() { return typeof window !== 'undefined'; } +/** + *@name formatCurrency + * @description Format the currency based on the currency code + */ export function formatCurrency(currencyCode: string, value: string | number) { return new Intl.NumberFormat('en-US', { style: 'currency', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4a3e0619..7c0354780 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -103,7 +103,7 @@ importers: version: 5.28.6(react@18.2.0) '@tanstack/react-query-next-experimental': specifier: ^5.28.14 - version: 5.28.14(@tanstack/react-query@5.28.6)(next@14.2.0-canary.61)(react@18.2.0) + version: 5.28.14(@tanstack/react-query@5.28.6)(next@14.2.0-canary.62)(react@18.2.0) '@tanstack/react-table': specifier: ^8.15.3 version: 8.15.3(react-dom@18.2.0)(react@18.2.0) @@ -112,7 +112,7 @@ importers: version: 3.6.0 edge-csrf: specifier: ^1.0.9 - version: 1.0.9(next@14.2.0-canary.61) + version: 1.0.9(next@14.2.0-canary.62) i18next: specifier: ^23.10.1 version: 23.10.1 @@ -123,11 +123,11 @@ importers: specifier: ^0.363.0 version: 0.363.0(react@18.2.0) next: - specifier: 14.2.0-canary.61 - version: 14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0) + specifier: 14.2.0-canary.62 + version: 14.2.0-canary.62(react-dom@18.2.0)(react@18.2.0) next-sitemap: specifier: ^4.2.3 - version: 4.2.3(next@14.2.0-canary.61) + version: 4.2.3(next@14.2.0-canary.62) next-themes: specifier: 0.3.0 version: 0.3.0(react-dom@18.2.0)(react@18.2.0) @@ -2302,8 +2302,8 @@ packages: resolution: {integrity: sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==} dev: false - /@next/env@14.2.0-canary.61: - resolution: {integrity: sha512-Ueqse8kdwaoebGrpSo60M4/cjFaMJEE7BMsKZufYwZDTlE0qXw7N4GsdVpUZzJG00sXf6CoTnCU1lCTPrUMC4g==} + /@next/env@14.2.0-canary.62: + resolution: {integrity: sha512-K5lmKK/TalagQELw3W0hKDXmNGGXY3Zxw3yH27y9DOT7evhiJvK2Ywq5uN4lEjYHkeW+QbyC/OjUIcK3RUSHbQ==} dev: false /@next/eslint-plugin-next@14.1.4: @@ -2330,8 +2330,8 @@ packages: dev: false optional: true - /@next/swc-darwin-arm64@14.2.0-canary.61: - resolution: {integrity: sha512-mMlp2/hvtaBbCY5qYhuvAqX9Z/aFC+Rgme4FjFSxq2C3TC/mL3G4fVG/TVl7bqjikKCxSvJgiWXRwvhIaqGktw==} + /@next/swc-darwin-arm64@14.2.0-canary.62: + resolution: {integrity: sha512-Cm53nqD/u7I1wo4xeULBZ6YjThK7Mk+ThaoYJu69varPPHsahpzbf/rM3ZkW3UB5Cgl5I7N3mNIb+Z9U/JZemw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -2357,8 +2357,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64@14.2.0-canary.61: - resolution: {integrity: sha512-4bEjO0WK6keRi972eAY1AfvTXOQRHnM59klNqnUh5zfalbi7VkEdluhYAZOop2NycCHjF+m8p+ytYtrF1uCO1Q==} + /@next/swc-darwin-x64@14.2.0-canary.62: + resolution: {integrity: sha512-2cSC0EOiJHe9kQad5TR/tXJuIc85JLBUeRl4x20jdsa0oIuOdsvksPA9TAROWLebuIkysPAsfmrbCwlKZk5yDw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -2384,8 +2384,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu@14.2.0-canary.61: - resolution: {integrity: sha512-wIXc3EdxrETlL2XwlGlLQkMU9godhNSMAXxiJotd/mhN3K4iKajPahAStvFxY2Zwc/on2IBa0NpUGpzDONNt9A==} + /@next/swc-linux-arm64-gnu@14.2.0-canary.62: + resolution: {integrity: sha512-Iow3tpn05nK2hW1nBzk1rCEVgbwakvlPViFZMxYg4FxEEoIcxcsxTMnG7sjJGmgrzCW7vfCVc+AM3Gy6bZXxqg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2411,8 +2411,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl@14.2.0-canary.61: - resolution: {integrity: sha512-95aMF55sq2N6+5iLEqxCfz7ccYMBURQ8D0KYmcq+rMJTE5z/qvxEToSJWAbV4jGyd2Eq/vXjPdR1rFytv2FnOw==} + /@next/swc-linux-arm64-musl@14.2.0-canary.62: + resolution: {integrity: sha512-dTugxbWEi95dNFn59C7RYuNTJ2jOVbDgD9lJmFtAJO46XPtN8IySJSe/5zB9YECA1apK2xWf5XaSbpuh5vWT8Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2438,8 +2438,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu@14.2.0-canary.61: - resolution: {integrity: sha512-LWG5OC9hNSCYtDb+7MQcIjE1PO70Sho+ZJkqJnmLxJ08Atp/nJQBo9nAMjORdcO5Nz+hPNVY5vmrY+5Fl5kadw==} + /@next/swc-linux-x64-gnu@14.2.0-canary.62: + resolution: {integrity: sha512-yGKHq4PfPgQO+IVWVOxbdv5pdIib/jwr62NsPKbY+t16gDB6RNTPhOcuhkQTvDBYlh+VF3vmhenlM5Ci0W5QQQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2465,8 +2465,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl@14.2.0-canary.61: - resolution: {integrity: sha512-EjOXbSmDTPVi8xkOix4/WYJM6OUert+lfBtdUJBRba+oGiRw/mheih8FliFZKFOmQbPYj67A9z/QCus2ZDnfSw==} + /@next/swc-linux-x64-musl@14.2.0-canary.62: + resolution: {integrity: sha512-Nw/l0Z4jzAL5VP1Z2mjNAMF7n+9aOTZgFJCtJ6C0aBf5rvZY3BrVDXblK57v6q1bWqU6FRGYmDava3h4B2i0hQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2492,8 +2492,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc@14.2.0-canary.61: - resolution: {integrity: sha512-TK8oV4ozzUGWAwvZp/0SBsNgAUhrUFLWCMSXsFHz+YMRjHg7nT0KdK8BYh2Ln4Qt0jjDTUHbI1jaQKxmSMEMmA==} + /@next/swc-win32-arm64-msvc@14.2.0-canary.62: + resolution: {integrity: sha512-FgS+pzblgiGe1iA2zvIxH5FTz/NVkXknhVgE3g0A5pIQeIfHn5hbki501fCBKvYujhsP094pSGePI9Hi35KFYA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -2519,8 +2519,8 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc@14.2.0-canary.61: - resolution: {integrity: sha512-i0iWCehuLKDOfVbQ6MEKG9v0lfcJU0DPWkYINFSi6p3fkFobI/+7DVT3KvYH5VVng/+opx+pA6cesV5eyQnBtw==} + /@next/swc-win32-ia32-msvc@14.2.0-canary.62: + resolution: {integrity: sha512-1cns8tyYICpspnhVC6FoRmd2Nal7uSXLPW4l1jX0+ofpifcmRy6Lra127/kdl8l+00W6ERQ/QAhx8uiYrw3VGQ==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -2546,8 +2546,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc@14.2.0-canary.61: - resolution: {integrity: sha512-WB0UjpWcu+oXQOMFDTHDZWKcL2jiXeQfN+1RRkb0x7ZjVxvA/O66vOJE08fLSu7rdymLiGXxX+AKlGFq1Tpisg==} + /@next/swc-win32-x64-msvc@14.2.0-canary.62: + resolution: {integrity: sha512-67gfnbOVzVrg4lsRhE9qHQegpPl/ljHMNFw4JyIOlLmCG7daHe6wgKmXGAyYBSZ6F6P9HiQWHcqU/qTHtw2lFw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -5038,7 +5038,7 @@ packages: /@tanstack/query-core@5.28.6: resolution: {integrity: sha512-hnhotV+DnQtvtR3jPvbQMPNMW4KEK0J4k7c609zJ8muiNknm+yoDyMHmxTWM5ZnlZpsz0zOxYFr+mzRJNHWJsA==} - /@tanstack/react-query-next-experimental@5.28.14(@tanstack/react-query@5.28.6)(next@14.2.0-canary.61)(react@18.2.0): + /@tanstack/react-query-next-experimental@5.28.14(@tanstack/react-query@5.28.6)(next@14.2.0-canary.62)(react@18.2.0): resolution: {integrity: sha512-gGHx3uJkZNYYpFNFk8eEo96ssiFE2OmYA49wszHxHrtO5nL7kzRcnJF8SALGpqSEjo5D3fLMH24MrhbBsO0sig==} peerDependencies: '@tanstack/react-query': ^5.28.14 @@ -5046,7 +5046,7 @@ packages: react: ^18.0.0 dependencies: '@tanstack/react-query': 5.28.6(react@18.2.0) - next: 14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0) + next: 14.2.0-canary.62(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 dev: false @@ -6858,12 +6858,12 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - /edge-csrf@1.0.9(next@14.2.0-canary.61): + /edge-csrf@1.0.9(next@14.2.0-canary.62): resolution: {integrity: sha512-3F89YTh42UDdISr3s9AEcgJDLi4ysgjGfnybzF0LuZGaG2W31h1ZwgWwEQBLMj04lAklcP4XHZYi7vk9o8zcbg==} peerDependencies: next: ^13.0.0 || ^14.0.0 dependencies: - next: 14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0) + next: 14.2.0-canary.62(react-dom@18.2.0)(react@18.2.0) dev: false /editorconfig@1.0.4: @@ -9648,7 +9648,7 @@ packages: - supports-color dev: false - /next-sitemap@4.2.3(next@14.2.0-canary.61): + /next-sitemap@4.2.3(next@14.2.0-canary.62): resolution: {integrity: sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==} engines: {node: '>=14.18'} hasBin: true @@ -9659,7 +9659,7 @@ packages: '@next/env': 13.5.6 fast-glob: 3.3.2 minimist: 1.2.8 - next: 14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0) + next: 14.2.0-canary.62(react-dom@18.2.0)(react@18.2.0) dev: false /next-themes@0.3.0(react-dom@18.2.0)(react@18.2.0): @@ -9751,8 +9751,8 @@ packages: - babel-plugin-macros dev: false - /next@14.2.0-canary.61(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-UbdoNkGX04TO0Q0N3k7fmiNCliE1yihVBHd/nwg2zMnpjB6dGU3r1UNgCBpfUUlrs1t19FAWazfVQANOOfBT4w==} + /next@14.2.0-canary.62(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-SsS+fpJ/anrtLgeCC76V9WOlreZanUYsuKsRMx+FDwOJ3ZnbZkohu3+RRLIQM1vtWcp707iV11+OlF/qgOldCA==} engines: {node: '>=18.17.0'} hasBin: true peerDependencies: @@ -9769,7 +9769,7 @@ packages: sass: optional: true dependencies: - '@next/env': 14.2.0-canary.61 + '@next/env': 14.2.0-canary.62 '@swc/helpers': 0.5.5 busboy: 1.6.0 caniuse-lite: 1.0.30001600 @@ -9779,15 +9779,15 @@ packages: react-dom: 18.2.0(react@18.2.0) styled-jsx: 5.1.1(react@18.2.0) optionalDependencies: - '@next/swc-darwin-arm64': 14.2.0-canary.61 - '@next/swc-darwin-x64': 14.2.0-canary.61 - '@next/swc-linux-arm64-gnu': 14.2.0-canary.61 - '@next/swc-linux-arm64-musl': 14.2.0-canary.61 - '@next/swc-linux-x64-gnu': 14.2.0-canary.61 - '@next/swc-linux-x64-musl': 14.2.0-canary.61 - '@next/swc-win32-arm64-msvc': 14.2.0-canary.61 - '@next/swc-win32-ia32-msvc': 14.2.0-canary.61 - '@next/swc-win32-x64-msvc': 14.2.0-canary.61 + '@next/swc-darwin-arm64': 14.2.0-canary.62 + '@next/swc-darwin-x64': 14.2.0-canary.62 + '@next/swc-linux-arm64-gnu': 14.2.0-canary.62 + '@next/swc-linux-arm64-musl': 14.2.0-canary.62 + '@next/swc-linux-x64-gnu': 14.2.0-canary.62 + '@next/swc-linux-x64-musl': 14.2.0-canary.62 + '@next/swc-win32-arm64-msvc': 14.2.0-canary.62 + '@next/swc-win32-ia32-msvc': 14.2.0-canary.62 + '@next/swc-win32-x64-msvc': 14.2.0-canary.62 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros