Deps Update, CSSNano, Sentry env (#210)
1. Update dependencies 2. Use cssnano for production 3. Assign an environment variable to Sentry's environment settings 4. `Pill` now accepts React Nodes so we can pass translations using Trans component 5. Switch to mailpit API during tests 6. Do not require Email Sender to be of type email and add proper error messages
This commit is contained in:
committed by
GitHub
parent
bd723dccce
commit
a45fda44cf
@@ -127,7 +127,7 @@ class ConnectivityService {
|
||||
}
|
||||
|
||||
const webhooksSecret = await getVariable(
|
||||
'STRIPE_WEBHOOKS_SECRET',
|
||||
'STRIPE_WEBHOOK_SECRET',
|
||||
this.mode,
|
||||
);
|
||||
|
||||
|
||||
@@ -1045,6 +1045,39 @@ export const envVariables: EnvVariableModel[] = [
|
||||
return z.enum(['baselime', 'sentry', '']).optional().safeParse(value);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_SENTRY_DSN',
|
||||
description: 'The Sentry DSN to use.',
|
||||
category: 'Monitoring',
|
||||
contextualValidation: {
|
||||
dependencies: [
|
||||
{
|
||||
variable: 'NEXT_PUBLIC_MONITORING_PROVIDER',
|
||||
condition: (value) => value === 'sentry',
|
||||
message:
|
||||
'NEXT_PUBLIC_SENTRY_DSN is required when NEXT_PUBLIC_MONITORING_PROVIDER is set to "sentry"',
|
||||
},
|
||||
],
|
||||
validate: ({ value }) => {
|
||||
return z
|
||||
.string()
|
||||
.min(
|
||||
1,
|
||||
`The NEXT_PUBLIC_SENTRY_DSN variable must be at least 1 character`,
|
||||
)
|
||||
.safeParse(value);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_SENTRY_ENVIRONMENT',
|
||||
description: 'The Sentry environment to use.',
|
||||
category: 'Monitoring',
|
||||
required: true,
|
||||
validate: ({ value }) => {
|
||||
return z.string().optional().safeParse(value);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_BASELIME_KEY',
|
||||
description: 'The Baselime key to use.',
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^4.1.3",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"lucide-react": "^0.477.0",
|
||||
"next": "15.2.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"lucide-react": "^0.479.0",
|
||||
"next": "15.2.2",
|
||||
"nodemailer": "^6.10.0",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
@@ -22,7 +22,7 @@
|
||||
"@kit/shared": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:*",
|
||||
"@tailwindcss/postcss": "^4.0.9",
|
||||
"@tailwindcss/postcss": "^4.0.13",
|
||||
"@types/node": "^22.13.4",
|
||||
"@types/nodemailer": "6.4.17",
|
||||
"@types/react": "19.0.10",
|
||||
@@ -30,7 +30,7 @@
|
||||
"babel-plugin-react-compiler": "19.0.0-beta-e1e972c-20250221",
|
||||
"pino-pretty": "^13.0.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"tailwindcss": "4.0.9",
|
||||
"tailwindcss": "4.0.13",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5.8.2",
|
||||
"zod": "^3.24.2"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@playwright/test": "^1.51.0",
|
||||
"@types/node": "^22.13.4",
|
||||
"node-html-parser": "^7.0.1",
|
||||
"totp-generator": "^1.0.0"
|
||||
|
||||
@@ -144,10 +144,12 @@ test.describe('Admin', () => {
|
||||
await page.getByTestId('admin-ban-account-button').click();
|
||||
await page.fill('[placeholder="Type CONFIRM to confirm"]', 'CONFIRM');
|
||||
await page.getByRole('button', { name: 'Ban User' }).click();
|
||||
|
||||
await expect(page.getByText('Banned')).toBeVisible();
|
||||
|
||||
// Now reactivate
|
||||
await page.getByTestId('admin-reactivate-account-button').click();
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'Reactivate User' }),
|
||||
).toBeVisible();
|
||||
@@ -323,28 +325,30 @@ async function createUser(
|
||||
} = {},
|
||||
) {
|
||||
const auth = new AuthPageObject(page);
|
||||
const password = 'testingpassword';
|
||||
const email = auth.createRandomEmail();
|
||||
|
||||
// sign up
|
||||
await page.goto('/auth/sign-up');
|
||||
|
||||
const email = `${(Math.random() * 1000000).toFixed(0)}@makerkit.dev`;
|
||||
|
||||
await auth.signUp({
|
||||
email,
|
||||
password: 'testingpassword',
|
||||
repeatPassword: 'testingpassword',
|
||||
password,
|
||||
repeatPassword: password,
|
||||
});
|
||||
|
||||
// confirm email
|
||||
await auth.visitConfirmEmailLink(email);
|
||||
|
||||
await page.goto('/home');
|
||||
|
||||
if (params.afterSignIn) {
|
||||
await params.afterSignIn();
|
||||
}
|
||||
|
||||
// sign out
|
||||
await auth.signOut();
|
||||
await page.waitForURL('/');
|
||||
|
||||
// return the email
|
||||
return email;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ export class AuthPageObject {
|
||||
}
|
||||
|
||||
createRandomEmail() {
|
||||
const value = Math.random() * 10000000000;
|
||||
const value = Math.random() * 10000000000000;
|
||||
|
||||
return `${value.toFixed(0)}@makerkit.dev`;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ test.describe('Password Reset Flow', () => {
|
||||
let email = '';
|
||||
|
||||
await expect(async () => {
|
||||
email = `test-${Math.random() * 10000}@makerkit.dev`;
|
||||
email = auth.createRandomEmail();
|
||||
|
||||
await page.goto('/auth/sign-up');
|
||||
|
||||
|
||||
@@ -1,7 +1,45 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import { parse } from 'node-html-parser';
|
||||
|
||||
type MessageSummary = {
|
||||
ID: string;
|
||||
MessageID: string;
|
||||
Read: boolean;
|
||||
From: {
|
||||
Name: string;
|
||||
Address: string;
|
||||
};
|
||||
To: Array<{
|
||||
Name: string;
|
||||
Address: string;
|
||||
}>;
|
||||
Cc: Array<any>;
|
||||
Bcc: Array<any>;
|
||||
ReplyTo: Array<any>;
|
||||
Subject: string;
|
||||
Created: string;
|
||||
Tags: Array<any>;
|
||||
Size: number;
|
||||
Attachments: number;
|
||||
Snippet: string;
|
||||
};
|
||||
|
||||
type MessagesResponse = {
|
||||
total: number;
|
||||
unread: number;
|
||||
count: number;
|
||||
messages_count: number;
|
||||
start: number;
|
||||
tags: Array<any>;
|
||||
messages: MessageSummary[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Mailbox class for interacting with the Mailpit mailbox API.
|
||||
*/
|
||||
export class Mailbox {
|
||||
static URL = 'http://127.0.0.1:54324';
|
||||
|
||||
constructor(private readonly page: Page) {}
|
||||
|
||||
async visitMailbox(
|
||||
@@ -11,28 +49,32 @@ export class Mailbox {
|
||||
subject?: string;
|
||||
},
|
||||
) {
|
||||
const mailbox = email.split('@')[0];
|
||||
|
||||
console.log(`Visiting mailbox ${email} ...`);
|
||||
|
||||
if (!mailbox) {
|
||||
if (!email) {
|
||||
throw new Error('Invalid email');
|
||||
}
|
||||
|
||||
const json = await this.getEmail(mailbox, params);
|
||||
const json = await this.getEmail(email, params);
|
||||
|
||||
if (!json?.body) {
|
||||
if (!json) {
|
||||
throw new Error('Email body was not found');
|
||||
}
|
||||
|
||||
console.log(`Email found for ${email}`, {
|
||||
id: json.id,
|
||||
subject: json.subject,
|
||||
date: json.date,
|
||||
console.log(`Email found for email: ${email}`, {
|
||||
expectedEmail: email,
|
||||
id: json.ID,
|
||||
subject: json.Subject,
|
||||
date: json.Date,
|
||||
to: json.To[0],
|
||||
text: json.Text,
|
||||
});
|
||||
|
||||
const html = (json.body as { html: string }).html;
|
||||
const el = parse(html);
|
||||
if (email !== json.To[0]!.Address) {
|
||||
throw new Error(`Email address mismatch. Expected ${email}, got ${json.To[0]!.Address}`);
|
||||
}
|
||||
|
||||
const el = parse(json.HTML);
|
||||
|
||||
const linkHref = el.querySelector('a')?.getAttribute('href');
|
||||
|
||||
@@ -51,27 +93,27 @@ export class Mailbox {
|
||||
* @param deleteAfter Whether to delete the email after retrieving the OTP
|
||||
* @returns The OTP code
|
||||
*/
|
||||
async getOtpFromEmail(email: string, deleteAfter: boolean = true) {
|
||||
const mailbox = email.split('@')[0];
|
||||
|
||||
async getOtpFromEmail(email: string, deleteAfter = false) {
|
||||
console.log(`Retrieving OTP from mailbox ${email} ...`);
|
||||
|
||||
if (!mailbox) {
|
||||
if (!email) {
|
||||
throw new Error('Invalid email');
|
||||
}
|
||||
|
||||
const json = await this.getEmail(mailbox, {
|
||||
const json = await this.getEmail(email, {
|
||||
deleteAfter,
|
||||
subject: `One-time password for Makerkit`,
|
||||
});
|
||||
|
||||
if (!json?.body) {
|
||||
if (!json) {
|
||||
throw new Error('Email body was not found');
|
||||
}
|
||||
|
||||
const html = (json.body as { html: string }).html;
|
||||
if (email !== json.To[0]!.Address) {
|
||||
throw new Error(`Email address mismatch. Expected ${email}, got ${json.To[0]!.Address}`);
|
||||
}
|
||||
|
||||
const text = html.match(
|
||||
const text = json.HTML.match(
|
||||
new RegExp(`Your one-time password is: (\\d{6})`),
|
||||
)?.[1];
|
||||
|
||||
@@ -84,49 +126,66 @@ export class Mailbox {
|
||||
}
|
||||
|
||||
async getEmail(
|
||||
mailbox: string,
|
||||
email: string,
|
||||
params: {
|
||||
deleteAfter: boolean;
|
||||
subject?: string;
|
||||
},
|
||||
) {
|
||||
const url = `http://127.0.0.1:54324/api/v1/mailbox/${mailbox}`;
|
||||
console.log(`Retrieving email from mailbox ${email}...`);
|
||||
|
||||
const url = `${Mailbox.URL}/api/v1/search?query=to:${email}`;
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch emails: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const json = (await response.json()) as Array<{
|
||||
id: string;
|
||||
subject: string;
|
||||
}>;
|
||||
const messagesResponse = (await response.json()) as MessagesResponse;
|
||||
|
||||
if (!json || !json.length) {
|
||||
console.log(`No emails found for mailbox ${mailbox}`);
|
||||
if (!messagesResponse || !messagesResponse.messages?.length) {
|
||||
console.log(`No emails found for mailbox ${email}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const message = params.subject
|
||||
? (() => {
|
||||
const filtered = json.filter(
|
||||
(item) => item.subject === params.subject,
|
||||
const filtered = messagesResponse.messages.filter(
|
||||
(item) => item.Subject === params.subject,
|
||||
);
|
||||
|
||||
console.log(
|
||||
`Found ${filtered.length} emails with subject ${params.subject}`,
|
||||
);
|
||||
|
||||
return filtered[filtered.length - 1];
|
||||
// retrieve the latest by timestamp
|
||||
return filtered.reduce((acc, item) => {
|
||||
if (
|
||||
new Date(acc.Created).getTime() < new Date(item.Created).getTime()
|
||||
) {
|
||||
return item;
|
||||
}
|
||||
|
||||
return acc;
|
||||
});
|
||||
})()
|
||||
: json[0];
|
||||
: messagesResponse.messages.reduce((acc, item) => {
|
||||
if (
|
||||
new Date(acc.Created).getTime() < new Date(item.Created).getTime()
|
||||
) {
|
||||
return item;
|
||||
}
|
||||
|
||||
console.log(`Message: ${JSON.stringify(message)}`);
|
||||
return acc;
|
||||
});
|
||||
|
||||
const messageId = message?.id;
|
||||
const messageUrl = `${url}/${messageId}`;
|
||||
if (!message) {
|
||||
throw new Error('No message found');
|
||||
}
|
||||
|
||||
const messageId = message.ID;
|
||||
const messageUrl = `${Mailbox.URL}/api/v1/message/${messageId}`;
|
||||
|
||||
const messageResponse = await fetch(messageUrl);
|
||||
|
||||
@@ -138,8 +197,9 @@ export class Mailbox {
|
||||
if (params.deleteAfter) {
|
||||
console.log(`Deleting email ${messageId} ...`);
|
||||
|
||||
const res = await fetch(messageUrl, {
|
||||
const res = await fetch(`${Mailbox.URL}/api/v1/messages`, {
|
||||
method: 'DELETE',
|
||||
body: JSON.stringify({ Ids: [messageId] }),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
@@ -147,6 +207,35 @@ export class Mailbox {
|
||||
}
|
||||
}
|
||||
|
||||
return await messageResponse.json();
|
||||
return (await messageResponse.json()) as Promise<{
|
||||
ID: string;
|
||||
MessageID: string;
|
||||
From: {
|
||||
Name: string;
|
||||
Address: string;
|
||||
};
|
||||
To: Array<{
|
||||
Name: string;
|
||||
Address: string;
|
||||
}>;
|
||||
Cc: Array<any>;
|
||||
Bcc: Array<any>;
|
||||
ReplyTo: Array<any>;
|
||||
ReturnPath: string;
|
||||
Subject: string;
|
||||
ListUnsubscribe: {
|
||||
Header: string;
|
||||
Links: Array<any>;
|
||||
Errors: string;
|
||||
HeaderPost: string;
|
||||
};
|
||||
Date: string;
|
||||
Tags: Array<any>;
|
||||
Text: string;
|
||||
HTML: string;
|
||||
Size: number;
|
||||
Inline: Array<any>;
|
||||
Attachments: Array<any>;
|
||||
}>;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhY
|
||||
SUPABASE_DB_WEBHOOK_SECRET=WEBHOOKSECRET
|
||||
|
||||
# EMAILS
|
||||
EMAIL_SENDER=test@makerkit.dev
|
||||
EMAIL_SENDER="Makerkit <admin@makerkit.dev>"
|
||||
EMAIL_PORT=54325
|
||||
EMAIL_HOST=localhost
|
||||
EMAIL_TLS=false
|
||||
|
||||
@@ -57,13 +57,13 @@
|
||||
"@marsidev/react-turnstile": "^1.1.0",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.477.0",
|
||||
"next": "15.2.1",
|
||||
"lucide-react": "^0.479.0",
|
||||
"next": "15.2.2",
|
||||
"next-sitemap": "^4.2.3",
|
||||
"next-themes": "0.4.4",
|
||||
"next-themes": "0.4.6",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
@@ -77,18 +77,19 @@
|
||||
"@kit/eslint-config": "workspace:*",
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@next/bundle-analyzer": "15.2.1",
|
||||
"@tailwindcss/postcss": "^4.0.9",
|
||||
"@next/bundle-analyzer": "15.2.2",
|
||||
"@tailwindcss/postcss": "^4.0.13",
|
||||
"@types/node": "^22.13.4",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"babel-plugin-react-compiler": "19.0.0-beta-e1e972c-20250221",
|
||||
"cssnano": "^7.0.6",
|
||||
"dotenv-cli": "^8.0.0",
|
||||
"pino-pretty": "^13.0.0",
|
||||
"prettier": "^3.5.3",
|
||||
"supabase": "^2.15.8",
|
||||
"tailwindcss": "4.0.9",
|
||||
"supabase": "^2.19.5",
|
||||
"tailwindcss": "4.0.13",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
|
||||
},
|
||||
};
|
||||
@@ -76,6 +76,9 @@ redirect_uri = ""
|
||||
# or any other third-party OIDC providers.
|
||||
url = ""
|
||||
|
||||
[auth.rate_limit]
|
||||
email_sent = 1000
|
||||
|
||||
[auth.email.template.invite]
|
||||
subject = "You are invited to Makerkit"
|
||||
content_path = "./supabase/templates/invite-user.html"
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"@types/react": "19.0.10",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.477.0",
|
||||
"next": "15.2.1",
|
||||
"lucide-react": "^0.479.0",
|
||||
"next": "15.2.2",
|
||||
"react": "19.0.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-i18next": "^15.4.1",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:*",
|
||||
"@types/react": "19.0.10",
|
||||
"next": "15.2.1",
|
||||
"next": "15.2.2",
|
||||
"react": "19.0.0",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
"./components": "./src/components/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@stripe/react-stripe-js": "^3.3.0",
|
||||
"@stripe/stripe-js": "^5.8.0",
|
||||
"@stripe/react-stripe-js": "^3.4.0",
|
||||
"@stripe/stripe-js": "^6.0.0",
|
||||
"stripe": "^17.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -29,7 +29,7 @@
|
||||
"@kit/ui": "workspace:*",
|
||||
"@types/react": "19.0.10",
|
||||
"date-fns": "^4.1.0",
|
||||
"next": "15.2.1",
|
||||
"next": "15.2.2",
|
||||
"react": "19.0.0",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"./api": "./src/server/api.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"nanoid": "^5.1.2"
|
||||
"nanoid": "^5.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hookform/resolvers": "^4.1.3",
|
||||
@@ -35,12 +35,12 @@
|
||||
"@kit/ui": "workspace:*",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"lucide-react": "^0.477.0",
|
||||
"next": "15.2.1",
|
||||
"next-themes": "0.4.4",
|
||||
"lucide-react": "^0.479.0",
|
||||
"next": "15.2.2",
|
||||
"next-themes": "0.4.6",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
"@makerkit/data-loader-supabase-core": "^0.0.8",
|
||||
"@makerkit/data-loader-supabase-nextjs": "^1.2.3",
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"@types/react": "19.0.10",
|
||||
"lucide-react": "^0.477.0",
|
||||
"next": "15.2.1",
|
||||
"lucide-react": "^0.479.0",
|
||||
"next": "15.2.2",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
"@marsidev/react-turnstile": "^1.1.0",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"@types/react": "19.0.10",
|
||||
"lucide-react": "^0.477.0",
|
||||
"next": "15.2.1",
|
||||
"lucide-react": "^0.479.0",
|
||||
"next": "15.2.2",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-i18next": "^15.4.1",
|
||||
"sonner": "^2.0.1",
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:*",
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"@types/react": "19.0.10",
|
||||
"lucide-react": "^0.477.0",
|
||||
"lucide-react": "^0.479.0",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-i18next": "^15.4.1"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"./webhooks": "./src/server/services/webhooks/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"nanoid": "^5.1.2"
|
||||
"nanoid": "^5.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hookform/resolvers": "^4.1.3",
|
||||
@@ -33,14 +33,14 @@
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:*",
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.477.0",
|
||||
"next": "15.2.1",
|
||||
"lucide-react": "^0.479.0",
|
||||
"next": "15.2.2",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
|
||||
@@ -8,16 +8,33 @@ import { Database } from '@kit/supabase/database';
|
||||
type Invitation = Database['public']['Tables']['invitations']['Row'];
|
||||
|
||||
const invitePath = '/join';
|
||||
|
||||
const siteURL = process.env.NEXT_PUBLIC_SITE_URL;
|
||||
const productName = process.env.NEXT_PUBLIC_PRODUCT_NAME ?? '';
|
||||
const emailSender = process.env.EMAIL_SENDER;
|
||||
|
||||
const env = z
|
||||
.object({
|
||||
invitePath: z.string().min(1),
|
||||
siteURL: z.string().min(1),
|
||||
productName: z.string(),
|
||||
emailSender: z.string().email(),
|
||||
invitePath: z
|
||||
.string({
|
||||
required_error: 'The property invitePath is required',
|
||||
})
|
||||
.min(1),
|
||||
siteURL: z
|
||||
.string({
|
||||
required_error: 'NEXT_PUBLIC_SITE_URL is required',
|
||||
})
|
||||
.min(1),
|
||||
productName: z
|
||||
.string({
|
||||
required_error: 'NEXT_PUBLIC_PRODUCT_NAME is required',
|
||||
})
|
||||
.min(1),
|
||||
emailSender: z
|
||||
.string({
|
||||
required_error: 'EMAIL_SENDER is required',
|
||||
})
|
||||
.min(1),
|
||||
})
|
||||
.parse({
|
||||
invitePath,
|
||||
|
||||
@@ -76,7 +76,9 @@ class AccountWebhooksService {
|
||||
return z
|
||||
.object({
|
||||
productName: z.string(),
|
||||
fromEmail: z.string().email(),
|
||||
fromEmail: z.string({
|
||||
required_error: 'EMAIL_SENDER is required',
|
||||
}).min(1),
|
||||
})
|
||||
.parse({
|
||||
productName,
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/shared": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"next": "15.2.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"next": "15.2.2",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-i18next": "^15.4.1"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"./config/server": "./src/sentry.client.server.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/nextjs": "^9.3.0",
|
||||
"@sentry/nextjs": "^9.5.0",
|
||||
"import-in-the-middle": "1.13.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -39,18 +39,25 @@ export class SentryMonitoringService implements MonitoringService {
|
||||
}
|
||||
|
||||
private async initialize() {
|
||||
const environment =
|
||||
process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT ?? process.env.VERCEL_ENV;
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
const { initializeSentryBrowserClient } = await import(
|
||||
'../sentry.client.config'
|
||||
);
|
||||
|
||||
initializeSentryBrowserClient();
|
||||
initializeSentryBrowserClient({
|
||||
environment,
|
||||
});
|
||||
} else {
|
||||
const { initializeSentryServerClient } = await import(
|
||||
'../sentry.server.config'
|
||||
);
|
||||
|
||||
initializeSentryServerClient();
|
||||
initializeSentryServerClient({
|
||||
environment,
|
||||
});
|
||||
}
|
||||
|
||||
this.readyResolver?.();
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"@kit/supabase": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"next": "15.2.1",
|
||||
"next": "15.2.2",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"typesVersions": {
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@supabase/ssr": "^0.5.2",
|
||||
"@supabase/supabase-js": "2.49.1",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"@types/react": "19.0.10",
|
||||
"next": "15.2.1",
|
||||
"next": "15.2.2",
|
||||
"react": "19.0.0",
|
||||
"server-only": "^0.0.1",
|
||||
"zod": "^3.24.2"
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "1.0.4",
|
||||
"input-otp": "1.4.2",
|
||||
"lucide-react": "^0.477.0",
|
||||
"lucide-react": "^0.479.0",
|
||||
"react-top-loading-bar": "3.0.2",
|
||||
"recharts": "2.15.1",
|
||||
"tailwind-merge": "^3.0.2"
|
||||
@@ -43,21 +43,21 @@
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@tanstack/react-query": "5.67.1",
|
||||
"@tanstack/react-query": "5.67.3",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"eslint": "^9.21.0",
|
||||
"next": "15.2.1",
|
||||
"next-themes": "0.4.4",
|
||||
"eslint": "^9.22.0",
|
||||
"next": "15.2.2",
|
||||
"next-themes": "0.4.6",
|
||||
"prettier": "^3.5.3",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-i18next": "^15.4.1",
|
||||
"sonner": "^2.0.1",
|
||||
"tailwindcss": "4.0.9",
|
||||
"tailwindcss": "4.0.13",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"typescript": "^5.8.2",
|
||||
"zod": "^3.24.2"
|
||||
|
||||
@@ -5,7 +5,7 @@ import { GradientSecondaryText } from './gradient-secondary-text';
|
||||
|
||||
export const Pill: React.FC<
|
||||
React.HTMLAttributes<HTMLHeadingElement> & {
|
||||
label?: string;
|
||||
label?: React.ReactNode;
|
||||
asChild?: boolean;
|
||||
}
|
||||
> = function PillComponent({ className, asChild, ...props }) {
|
||||
|
||||
2055
pnpm-lock.yaml
generated
2055
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -13,16 +13,16 @@
|
||||
"format": "prettier --check \"**/*.{js,json}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@next/eslint-plugin-next": "15.2.1",
|
||||
"@next/eslint-plugin-next": "15.2.2",
|
||||
"@types/eslint": "9.6.1",
|
||||
"eslint-config-next": "15.2.1",
|
||||
"eslint-config-next": "15.2.2",
|
||||
"eslint-config-turbo": "^2.4.4",
|
||||
"typescript-eslint": "8.26.0"
|
||||
"typescript-eslint": "8.26.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kit/prettier-config": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint": "^9.22.0",
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
"prettier": "@kit/prettier-config"
|
||||
|
||||
Reference in New Issue
Block a user