diff --git a/apps/marketing/src/app/(marketing)/blog/[post]/opengraph-image.tsx b/apps/marketing/src/app/(marketing)/blog/[post]/opengraph-image.tsx
new file mode 100644
index 000000000..f9987dd27
--- /dev/null
+++ b/apps/marketing/src/app/(marketing)/blog/[post]/opengraph-image.tsx
@@ -0,0 +1,76 @@
+import { ImageResponse } from 'next/server';
+
+import { allBlogPosts } from 'contentlayer/generated';
+
+export const runtime = 'edge';
+
+export const size = {
+ width: 1200,
+ height: 630,
+};
+
+export const contentType = 'image/png';
+
+type BlogPostOpenGraphImageProps = {
+ params: { post: string };
+};
+
+export default async function BlogPostOpenGraphImage({ params }: BlogPostOpenGraphImageProps) {
+ const blogPost = allBlogPosts.find((post) => post._raw.flattenedPath === `blog/${params.post}`);
+
+ if (!blogPost) {
+ return null;
+ }
+
+ // The long urls are needed for a compiler optimisation on the Next.js side, lifting this up
+ // to a constant will break og image generation.
+ const [interBold, interRegular, backgroundImage, logoImage] = await Promise.all([
+ fetch(new URL('./../../../../assets/inter-bold.ttf', import.meta.url)).then(async (res) =>
+ res.arrayBuffer(),
+ ),
+ fetch(new URL('./../../../../assets/inter-regular.ttf', import.meta.url)).then(async (res) =>
+ res.arrayBuffer(),
+ ),
+ fetch(new URL('./../../../../assets/background-blog-og.png', import.meta.url)).then(
+ async (res) => res.arrayBuffer(),
+ ),
+ fetch(new URL('./../../../../../public/logo.png', import.meta.url)).then(async (res) =>
+ res.arrayBuffer(),
+ ),
+ ]);
+
+ return new ImageResponse(
+ (
+
+ {/* @ts-expect-error Lack of typing from ImageResponse */}
+

+
+ {/* @ts-expect-error Lack of typing from ImageResponse */}
+

+
+
+ {blogPost.title}
+
+
+
Written by {blogPost.authorName}
+
+ ),
+ {
+ ...size,
+ fonts: [
+ {
+ name: 'Inter',
+ data: interRegular,
+ style: 'normal',
+ weight: 400,
+ },
+ {
+ name: 'Inter',
+ data: interBold,
+ style: 'normal',
+ weight: 700,
+ },
+ ],
+ },
+ );
+}
diff --git a/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx b/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx
index 5192dec32..7edf29ec2 100644
--- a/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx
+++ b/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx
@@ -17,7 +17,9 @@ export const generateMetadata = ({ params }: { params: { post: string } }) => {
notFound();
}
- return { title: `Documenso - ${blogPost.title}` };
+ return {
+ title: `Documenso - ${blogPost.title}`,
+ };
};
const mdxComponents: MDXComponents = {
diff --git a/apps/marketing/src/app/(marketing)/claimed/page.tsx b/apps/marketing/src/app/(marketing)/claimed/page.tsx
index ce748006e..f56ae2b26 100644
--- a/apps/marketing/src/app/(marketing)/claimed/page.tsx
+++ b/apps/marketing/src/app/(marketing)/claimed/page.tsx
@@ -27,7 +27,11 @@ export type ClaimedPlanPageProps = {
export default async function ClaimedPlanPage({ searchParams = {} }: ClaimedPlanPageProps) {
const { sessionId } = searchParams;
- const session = await stripe.checkout.sessions.retrieve(sessionId as string);
+ if (typeof sessionId !== 'string') {
+ redirect('/');
+ }
+
+ const session = await stripe.checkout.sessions.retrieve(sessionId);
const user = await prisma.user.findFirst({
where: {
@@ -157,7 +161,6 @@ export default async function ClaimedPlanPage({ searchParams = {} }: ClaimedPlan
{
const event = usePlausible();
const [period, setPeriod] = useState<'MONTHLY' | 'YEARLY'>(() =>
- // eslint-disable-next-line turbo/no-undeclared-env-vars
params?.get('planId') === process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID
? 'YEARLY'
: 'MONTHLY',
@@ -30,11 +29,9 @@ export const PricingTable = ({ className, ...props }: PricingTableProps) => {
const planId = useMemo(() => {
if (period === 'MONTHLY') {
- // eslint-disable-next-line turbo/no-undeclared-env-vars
return process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID;
}
- // eslint-disable-next-line turbo/no-undeclared-env-vars
return process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID;
}, [period]);
diff --git a/apps/marketing/src/components/(marketing)/widget.tsx b/apps/marketing/src/components/(marketing)/widget.tsx
index 15e15d04c..def90e0cd 100644
--- a/apps/marketing/src/components/(marketing)/widget.tsx
+++ b/apps/marketing/src/components/(marketing)/widget.tsx
@@ -139,7 +139,6 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
setTimeout(resolve, 1000);
});
- // eslint-disable-next-line turbo/no-undeclared-env-vars
const planId = process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID;
const claimPlanInput = signatureDataUrl
@@ -147,7 +146,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
name,
email,
planId,
- signatureDataUrl: signatureDataUrl!,
+ signatureDataUrl: signatureDataUrl,
signatureText: null,
}
: {
@@ -155,7 +154,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
email,
planId,
signatureDataUrl: null,
- signatureText: signatureText!,
+ signatureText: signatureText ?? '',
};
const [result] = await Promise.all([claimPlan(claimPlanInput), delay]);
diff --git a/apps/marketing/src/pages/api/claim-plan/index.ts b/apps/marketing/src/pages/api/claim-plan/index.ts
index a2e4108d2..abad354a8 100644
--- a/apps/marketing/src/pages/api/claim-plan/index.ts
+++ b/apps/marketing/src/pages/api/claim-plan/index.ts
@@ -43,7 +43,6 @@ export default async function handler(
if (user && user.Subscription.length > 0) {
return res.status(200).json({
- // eslint-disable-next-line turbo/no-undeclared-env-vars
redirectUrl: `${process.env.NEXT_PUBLIC_APP_URL}/login`,
});
}
@@ -104,7 +103,6 @@ export default async function handler(
mode: 'subscription',
metadata,
allow_promotion_codes: true,
- // eslint-disable-next-line turbo/no-undeclared-env-vars
success_url: `${process.env.NEXT_PUBLIC_SITE_URL}/claimed?sessionId={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_SITE_URL}/pricing?email=${encodeURIComponent(
email,
diff --git a/apps/marketing/src/pages/api/stripe/webhook/index.ts b/apps/marketing/src/pages/api/stripe/webhook/index.ts
index a0a4ccebb..3f3810fd4 100644
--- a/apps/marketing/src/pages/api/stripe/webhook/index.ts
+++ b/apps/marketing/src/pages/api/stripe/webhook/index.ts
@@ -17,14 +17,13 @@ import {
SigningStatus,
} from '@documenso/prisma/client';
-const log = (...args: any[]) => console.log('[stripe]', ...args);
+const log = (...args: unknown[]) => console.log('[stripe]', ...args);
export const config = {
api: { bodyParser: false },
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- // eslint-disable-next-line turbo/no-undeclared-env-vars
// if (!process.env.NEXT_PUBLIC_ALLOW_SUBSCRIPTIONS) {
// return res.status(500).json({
// success: false,
@@ -55,6 +54,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
log('event-type:', event.type);
if (event.type === 'checkout.session.completed') {
+ // This typecast is required since we don't want to create a guard for every event type
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const session = event.data.object as Stripe.Checkout.Session;
if (session.metadata?.source === 'landing') {
diff --git a/apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx b/apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx
index e1c9a79e1..7ed28feca 100644
--- a/apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx
+++ b/apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx
@@ -130,7 +130,13 @@ export const EditDocumentForm = ({
},
});
- router.refresh();
+ toast({
+ title: 'Document sent',
+ description: 'Your document has been sent successfully.',
+ duration: 5000,
+ });
+
+ router.push('/dashboard');
} catch (err) {
console.error(err);
diff --git a/apps/web/src/app/(signing)/sign/[token]/form.tsx b/apps/web/src/app/(signing)/sign/[token]/form.tsx
index 3666941dc..e18571e33 100644
--- a/apps/web/src/app/(signing)/sign/[token]/form.tsx
+++ b/apps/web/src/app/(signing)/sign/[token]/form.tsx
@@ -87,9 +87,6 @@ export const SigningForm = ({ document, recipient, fields }: SigningFormProps) =
className="h-44 w-full"
defaultValue={signature ?? undefined}
onChange={(value) => {
- console.log({
- signpadValue: value,
- });
setSignature(value);
}}
/>
diff --git a/apps/web/src/app/(signing)/sign/[token]/signature-field.tsx b/apps/web/src/app/(signing)/sign/[token]/signature-field.tsx
index 68a61fb67..cb70ea4db 100644
--- a/apps/web/src/app/(signing)/sign/[token]/signature-field.tsx
+++ b/apps/web/src/app/(signing)/sign/[token]/signature-field.tsx
@@ -63,11 +63,6 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => {
const onSign = async (source: 'local' | 'provider' = 'provider') => {
try {
- console.log({
- providedSignature,
- localSignature,
- });
-
if (!providedSignature && !localSignature) {
setShowSignatureModal(true);
return;
diff --git a/apps/web/src/components/(dashboard)/period-selector/types.ts b/apps/web/src/components/(dashboard)/period-selector/types.ts
index 4ebfe47f1..2b50f5d6c 100644
--- a/apps/web/src/components/(dashboard)/period-selector/types.ts
+++ b/apps/web/src/components/(dashboard)/period-selector/types.ts
@@ -1,5 +1,6 @@
export type PeriodSelectorValue = '' | '7d' | '14d' | '30d';
export const isPeriodSelectorValue = (value: unknown): value is PeriodSelectorValue => {
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return ['', '7d', '14d', '30d'].includes(value as string);
};
diff --git a/apps/web/src/components/forms/profile.tsx b/apps/web/src/components/forms/profile.tsx
index d65a0ce27..5b4045abb 100644
--- a/apps/web/src/components/forms/profile.tsx
+++ b/apps/web/src/components/forms/profile.tsx
@@ -21,7 +21,7 @@ import { FormErrorMessage } from '../form/form-error-message';
export const ZProfileFormSchema = z.object({
name: z.string().min(1),
- signature: z.string().min(1),
+ signature: z.string().min(1, 'Signature Pad cannot be empty'),
});
export type TProfileFormSchema = z.infer;
@@ -122,6 +122,7 @@ export const ProfileForm = ({ className, user }: ProfileFormProps) => {
/>
)}
/>
+
diff --git a/apps/web/src/middleware.ts b/apps/web/src/middleware.ts
index 2f393ce71..25bfbbb40 100644
--- a/apps/web/src/middleware.ts
+++ b/apps/web/src/middleware.ts
@@ -1,25 +1,23 @@
import { NextRequest, NextResponse } from 'next/server';
-export default function middleware(req: NextRequest) {
+import { getToken } from 'next-auth/jwt';
+
+export default async function middleware(req: NextRequest) {
if (req.nextUrl.pathname === '/') {
const redirectUrl = new URL('/documents', req.url);
return NextResponse.redirect(redirectUrl);
}
- // if (req.nextUrl.pathname.startsWith('/dashboard')) {
- // const token = await getToken({ req });
+ if (req.nextUrl.pathname.startsWith('/signin')) {
+ const token = await getToken({ req });
- // console.log('token', token);
+ if (token) {
+ const redirectUrl = new URL('/documents', req.url);
- // if (!token) {
- // console.log('has no token', req.url);
- // const redirectUrl = new URL('/signin', req.url);
- // redirectUrl.searchParams.set('callbackUrl', req.url);
-
- // return NextResponse.redirect(redirectUrl);
- // }
- // }
+ return NextResponse.redirect(redirectUrl);
+ }
+ }
return NextResponse.next();
}
diff --git a/apps/web/src/pages/api/claim-plan/index.ts b/apps/web/src/pages/api/claim-plan/index.ts
index a2e4108d2..abad354a8 100644
--- a/apps/web/src/pages/api/claim-plan/index.ts
+++ b/apps/web/src/pages/api/claim-plan/index.ts
@@ -43,7 +43,6 @@ export default async function handler(
if (user && user.Subscription.length > 0) {
return res.status(200).json({
- // eslint-disable-next-line turbo/no-undeclared-env-vars
redirectUrl: `${process.env.NEXT_PUBLIC_APP_URL}/login`,
});
}
@@ -104,7 +103,6 @@ export default async function handler(
mode: 'subscription',
metadata,
allow_promotion_codes: true,
- // eslint-disable-next-line turbo/no-undeclared-env-vars
success_url: `${process.env.NEXT_PUBLIC_SITE_URL}/claimed?sessionId={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_SITE_URL}/pricing?email=${encodeURIComponent(
email,
diff --git a/apps/web/src/pages/api/stripe/webhook/index.ts b/apps/web/src/pages/api/stripe/webhook/index.ts
index dd15d4d81..6c678a33c 100644
--- a/apps/web/src/pages/api/stripe/webhook/index.ts
+++ b/apps/web/src/pages/api/stripe/webhook/index.ts
@@ -17,14 +17,13 @@ import {
SigningStatus,
} from '@documenso/prisma/client';
-const log = (...args: any[]) => console.log('[stripe]', ...args);
+const log = (...args: unknown[]) => console.log('[stripe]', ...args);
export const config = {
api: { bodyParser: false },
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- // eslint-disable-next-line turbo/no-undeclared-env-vars
// if (!process.env.NEXT_PUBLIC_ALLOW_SUBSCRIPTIONS) {
// return res.status(500).json({
// success: false,
@@ -55,6 +54,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
log('event-type:', event.type);
if (event.type === 'checkout.session.completed') {
+ // This is required since we don't want to create a guard for every event type
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const session = event.data.object as Stripe.Checkout.Session;
if (session.metadata?.source === 'landing') {
diff --git a/package-lock.json b/package-lock.json
index 12c957494..1fa10b764 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16319,6 +16319,7 @@
}
},
"packages/ee": {
+ "name": "@documenso/ee",
"version": "1.0.0",
"license": "COMMERCIAL",
"dependencies": {
@@ -16362,7 +16363,7 @@
"packages/lib": {
"name": "@documenso/lib",
"version": "1.0.0",
- "license": "SEE LICENSE IN LICENSE",
+ "license": "MIT",
"dependencies": {
"@documenso/email": "*",
"@documenso/prisma": "*",
diff --git a/packages/lib/server-only/field/set-fields-for-document.ts b/packages/lib/server-only/field/set-fields-for-document.ts
index c54d35bc1..dc477bcea 100644
--- a/packages/lib/server-only/field/set-fields-for-document.ts
+++ b/packages/lib/server-only/field/set-fields-for-document.ts
@@ -84,6 +84,8 @@ export const setFieldsForDocument = async ({
})
: prisma.field.create({
data: {
+ // TODO: Rewrite this entire transaction because this is a mess
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
type: field.type!,
page: field.pageNumber,
positionX: field.pageX,
diff --git a/packages/lib/server-only/stripe/index.ts b/packages/lib/server-only/stripe/index.ts
index b2ab59fb9..505beaec8 100644
--- a/packages/lib/server-only/stripe/index.ts
+++ b/packages/lib/server-only/stripe/index.ts
@@ -1,7 +1,6 @@
import Stripe from 'stripe';
-// eslint-disable-next-line turbo/no-undeclared-env-vars
-export const stripe = new Stripe(process.env.NEXT_PRIVATE_STRIPE_API_KEY!, {
+export const stripe = new Stripe(process.env.NEXT_PRIVATE_STRIPE_API_KEY ?? '', {
apiVersion: '2022-11-15',
typescript: true,
});
diff --git a/packages/lib/server-only/user/update-password.ts b/packages/lib/server-only/user/update-password.ts
index 4133bc342..d987085ff 100644
--- a/packages/lib/server-only/user/update-password.ts
+++ b/packages/lib/server-only/user/update-password.ts
@@ -19,11 +19,13 @@ export const updatePassword = async ({ userId, password }: UpdatePasswordOptions
const hashedPassword = await hash(password, SALT_ROUNDS);
- // Compare the new password with the old password
- const isSamePassword = await compare(password, user.password as string);
+ if (user.password) {
+ // Compare the new password with the old password
+ const isSamePassword = await compare(password, user.password);
- if (isSamePassword) {
- throw new Error('Your new password cannot be the same as your old password.');
+ if (isSamePassword) {
+ throw new Error('Your new password cannot be the same as your old password.');
+ }
}
const updatedUser = await prisma.user.update({
diff --git a/packages/lib/types/find-result-set.ts b/packages/lib/types/find-result-set.ts
index 81b16f1ca..219b9b89c 100644
--- a/packages/lib/types/find-result-set.ts
+++ b/packages/lib/types/find-result-set.ts
@@ -1,5 +1,5 @@
export type FindResultSet = {
- data: T extends Array ? T : T[];
+ data: T extends Array ? T : T[];
count: number;
currentPage: number;
perPage: number;
diff --git a/packages/lib/types/is-document-status.ts b/packages/lib/types/is-document-status.ts
index 0666308a5..dbb5af489 100644
--- a/packages/lib/types/is-document-status.ts
+++ b/packages/lib/types/is-document-status.ts
@@ -1,5 +1,6 @@
import { DocumentStatus } from '@documenso/prisma/client';
export const isDocumentStatus = (value: unknown): value is DocumentStatus => {
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return Object.values(DocumentStatus).includes(value as DocumentStatus);
};
diff --git a/turbo.json b/turbo.json
index ab4460781..f7d3d342c 100644
--- a/turbo.json
+++ b/turbo.json
@@ -22,10 +22,13 @@
"globalEnv": [
"NEXTAUTH_URL",
"NEXTAUTH_SECRET",
+ "NEXT_PUBLIC_APP_URL",
"NEXT_PUBLIC_SITE_URL",
"NEXT_PUBLIC_POSTHOG_KEY",
"NEXT_PUBLIC_POSTHOG_HOST",
"NEXT_PUBLIC_FEATURE_BILLING_ENABLED",
+ "NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_YEARLY_PRICE_ID",
+ "NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID",
"NEXT_PRIVATE_DATABASE_URL",
"NEXT_PRIVATE_NEXT_AUTH_SECRET",
"NEXT_PRIVATE_GOOGLE_CLIENT_ID",
@@ -44,6 +47,7 @@
"NEXT_PRIVATE_SMTP_APIKEY",
"NEXT_PRIVATE_SMTP_SECURE",
"NEXT_PRIVATE_SMTP_FROM_NAME",
- "NEXT_PRIVATE_SMTP_FROM_ADDRESS"
+ "NEXT_PRIVATE_SMTP_FROM_ADDRESS",
+ "NEXT_PRIVATE_STRIPE_API_KEY"
]
-}
\ No newline at end of file
+}