|
|
|
@@ -285,6 +285,241 @@ npx shadcn-ui@latest add button --path=packages/src/ui/shadcn
|
|
|
|
|
|
|
|
|
|
We pass the `--path` flag to specify the path where the component should be installed. You may need to adjust the path based on your project structure.
|
|
|
|
|
|
|
|
|
|
**NB**: you may need to update the imports to the `cn` utility function to use the relative imports because it somehow breaks. Please do that.
|
|
|
|
|
|
|
|
|
|
## Writing Server Actions
|
|
|
|
|
|
|
|
|
|
In the large majority of cases - you will be writing React Server Actions to update data in your DB.
|
|
|
|
|
|
|
|
|
|
Makerkit ships with a utility to help you write these actions. The utility is called `enhanceAction` and we import it from `@kit/next/actions`.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
import { enhanceAction } from '@kit/next/actions';
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This utility helps us with three main things:
|
|
|
|
|
1. checks the user state (if the user is authenticated)
|
|
|
|
|
2. given a Zod schema, it validates the request body
|
|
|
|
|
3. given a captcha site key, it validates the captcha token
|
|
|
|
|
|
|
|
|
|
Fantastic, let's see how we can use it.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
'use server';
|
|
|
|
|
|
|
|
|
|
import { z } from 'zod';
|
|
|
|
|
import { enhanceAction } from '@kit/next/actions';
|
|
|
|
|
|
|
|
|
|
const ZodSchema = z.object({
|
|
|
|
|
email: z.string().email(),
|
|
|
|
|
password: z.string().min(6),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const myServerAction = enhanceAction(
|
|
|
|
|
async function (data, user) {
|
|
|
|
|
// 1. "data" has been validated against the Zod schema, and it's safe to use
|
|
|
|
|
// 2. "user" is the authenticated user
|
|
|
|
|
|
|
|
|
|
// ... your code here
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
schema: ZodSchema,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Using a Captcha token protection
|
|
|
|
|
|
|
|
|
|
If you want to protect your server actions with a captcha token, you can do so by passing the captcha site token to the `enhanceAction` function and setting the `captcha` flag to `true`.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
'use server';
|
|
|
|
|
|
|
|
|
|
import { enhanceAction } from '@kit/next/actions';
|
|
|
|
|
|
|
|
|
|
export const myServerAction = enhanceAction(
|
|
|
|
|
async function (data, user) {
|
|
|
|
|
// ... your code here
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
captcha: true,
|
|
|
|
|
schema: ZodSchema,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
When calling the server action, we must supply the captcha token in the request body.
|
|
|
|
|
|
|
|
|
|
The captcha token can be retrieved from the `useCaptchaToken` hook in the package `@kit/auth/captcha/client`.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
import { useCaptchaToken } from '@kit/auth/captcha/client';
|
|
|
|
|
|
|
|
|
|
function Component() {
|
|
|
|
|
const captchaToken = useCaptchaToken();
|
|
|
|
|
|
|
|
|
|
// ... your code here
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Now, when calling the server action, we can pass the captcha
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
import { useCaptchaToken } from '@kit/auth/captcha/client';
|
|
|
|
|
|
|
|
|
|
function Component() {
|
|
|
|
|
const captchaToken = useCaptchaToken();
|
|
|
|
|
|
|
|
|
|
const onSubmit = async (params: {
|
|
|
|
|
email: string;
|
|
|
|
|
password: string;
|
|
|
|
|
}) => {
|
|
|
|
|
const response = await myServerAction({
|
|
|
|
|
...params,
|
|
|
|
|
captchaToken,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ... your code here
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
NB: to use Captcha protection, you need to set the captcha token in the environment variables.
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
CAPTCHA_SECRET_TOKEN=
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
As a secret environment variable, please do not add it to the `.env` file. Instead, add it to the environment variables of your CI/CD system.
|
|
|
|
|
|
|
|
|
|
The only captcha provider supported is Cloudflare Turnstile.
|
|
|
|
|
|
|
|
|
|
## Writing API Route Handlers
|
|
|
|
|
|
|
|
|
|
You won't be writing too many API route handlers - but when you do, you can use the `enhanceRouteHandler` utility to help you with the following:
|
|
|
|
|
|
|
|
|
|
1. checks the user state (if the user is authenticated)
|
|
|
|
|
2. given a Zod schema, it validates the request body
|
|
|
|
|
3. given a captcha site key, it validates the captcha token
|
|
|
|
|
|
|
|
|
|
Fantastic, let's see how we can use it.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
'use server';
|
|
|
|
|
|
|
|
|
|
import { z } from 'zod';
|
|
|
|
|
|
|
|
|
|
import { enhanceRouteHandler } from '@kit/next/routes';
|
|
|
|
|
import { NextResponse } from 'next/server';
|
|
|
|
|
|
|
|
|
|
const ZodSchema = z.object({
|
|
|
|
|
email: z.string().email(),
|
|
|
|
|
password: z.string().min(6),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const POST = enhanceRouteHandler(
|
|
|
|
|
async function({ body, user, request }) {
|
|
|
|
|
// 1. "body" has been validated against the Zod schema, and it's safe to use
|
|
|
|
|
// 2. "user" is the authenticated user
|
|
|
|
|
// 3. "request" is the request object that contains the headers, query, etc.
|
|
|
|
|
|
|
|
|
|
// ... your code here
|
|
|
|
|
return NextResponse.json({
|
|
|
|
|
success: true,
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
schema: ZodSchema,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Using a Captcha token protection
|
|
|
|
|
|
|
|
|
|
If you want to protect your API route handlers with a captcha token, you can do so by passing the captcha site token to the `enhanceRouteHandler` function and setting the `captcha` flag to `true`.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
'use server';
|
|
|
|
|
|
|
|
|
|
import { enhanceRouteHandler } from '@kit/next/routes';
|
|
|
|
|
|
|
|
|
|
export const POST = enhanceRouteHandler(
|
|
|
|
|
async function({ body, user, request }) {
|
|
|
|
|
// ... your code here
|
|
|
|
|
return NextResponse.json({
|
|
|
|
|
success: true,
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
captcha: true,
|
|
|
|
|
schema: ZodSchema,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
When calling the API route handler, we must supply the captcha token in the request body.
|
|
|
|
|
|
|
|
|
|
The captcha token can be retrieved from the `useCaptchaToken` hook in the package `@kit/auth/captcha/client`.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
import { useCaptchaToken } from '@kit/auth/captcha/client';
|
|
|
|
|
|
|
|
|
|
function Component() {
|
|
|
|
|
const captchaToken = useCaptchaToken();
|
|
|
|
|
|
|
|
|
|
// ... your code here
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Now, when calling the API route handler, we can pass the captcha and the CSRF token.
|
|
|
|
|
|
|
|
|
|
NB: The CSRF token **must be added for all API routes** making mutations in routes that are outside `/api/*`. Routes inside `/api/*` are not protected by default as they're meant to be used externally.
|
|
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
|
import { useCaptchaToken } from '@kit/auth/captcha/client';
|
|
|
|
|
import { useCsrfToken } from '@kit/shared/hooks';
|
|
|
|
|
|
|
|
|
|
function Component() {
|
|
|
|
|
const captchaToken = useCaptchaToken();
|
|
|
|
|
const csrfToken = useCsrfToken();
|
|
|
|
|
|
|
|
|
|
const onSubmit = async (params: {
|
|
|
|
|
email: string;
|
|
|
|
|
password: string;
|
|
|
|
|
}) => {
|
|
|
|
|
const response = await fetch('/api/my-api-route', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
'x-csrf-token': csrfToken,
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
...params,
|
|
|
|
|
captchaToken,
|
|
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ... your code here
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
NB: to use Captcha protection, you need to set the captcha token in the environment variables.
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
CAPTCHA_SECRET_TOKEN=
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
As a secret environment variable, please do not add it to the `.env` file. Instead, add it to the environment variables of your CI/CD system.
|
|
|
|
|
|
|
|
|
|
The only captcha provider supported is Cloudflare Turnstile.
|
|
|
|
|
|
|
|
|
|
## Environment Variables
|
|
|
|
|
|
|
|
|
|
The majority of the environment variables are defined in the `apps/web/.env` file. These are the env variables
|
|
|
|
@@ -420,6 +655,8 @@ As the endpoint, remember to use the `/api/db/webhook` endpoint. If your APP url
|
|
|
|
|
|
|
|
|
|
#### Adding Database Webhooks from Supabase Studio
|
|
|
|
|
|
|
|
|
|
The below is only needed when going to production. The local development seed.sql script will add the webhooks for you.
|
|
|
|
|
|
|
|
|
|
While you can create a migration to add the database webhooks, you can also add them from the Supabase Studio.
|
|
|
|
|
|
|
|
|
|
1. Go to the Supabase Studio
|
|
|
|
|