Skip to content

Commit c87c476

Browse files
Merge pull request #682 from aXenDeveloper/feat/package_json_for_plugins
feat: Add package.json for plugins
2 parents 2f1c941 + dfeb025 commit c87c476

File tree

86 files changed

+3641
-2146
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+3641
-2146
lines changed

.github/workflows/bump_publish.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,21 +82,21 @@ jobs:
8282

8383
- name: Publish canary
8484
if: ${{ (github.event.inputs.mode == 'bump_and_publish' || github.event.inputs.mode == 'publish') && github.event.inputs.release == 'canary' }}
85-
run: pnpm publish --filter create-vitnode-app --filter @vitnode/core --filter @vitnode/config --filter @vitnode/blog --tag canary --no-git-checks --access public
85+
run: pnpm publish --filter create-vitnode-app --filter @vitnode/core --filter @vitnode/config --filter @vitnode/blog --filter @vitnode/nodemailer --filter @vitnode/resend --filter @vitnode/node-cron --tag canary --no-git-checks --access public
8686
env:
8787
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
8888
NPM_CONFIG_PROVENANCE: true
8989

9090
- name: Publish release candidate
9191
if: ${{ (github.event.inputs.mode == 'bump_and_publish' || github.event.inputs.mode == 'publish') && github.event.inputs.release == 'release-candidate' }}
92-
run: pnpm publish --filter create-vitnode-app --filter @vitnode/core --filter @vitnode/config --filter @vitnode/blog --tag rc --no-git-checks --access public
92+
run: pnpm publish --filter create-vitnode-app --filter @vitnode/core --filter @vitnode/config --filter @vitnode/blog --filter @vitnode/nodemailer --filter @vitnode/resend --filter @vitnode/node-cron --tag rc --no-git-checks --access public
9393
env:
9494
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
9595
NPM_CONFIG_PROVENANCE: true
9696

9797
- name: Publish stable
9898
if: ${{ (github.event.inputs.mode == 'bump_and_publish' || github.event.inputs.mode == 'publish') && github.event.inputs.release == 'stable' }}
99-
run: pnpm publish --filter create-vitnode-app --filter @vitnode/core --filter @vitnode/config --filter @vitnode/blog --tag latest --no-git-checks --access public
99+
run: pnpm publish --filter create-vitnode-app --filter @vitnode/core --filter @vitnode/config --filter @vitnode/blog --filter @vitnode/nodemailer --filter @vitnode/resend --filter @vitnode/node-cron --tag latest --no-git-checks --access public
100100
env:
101101
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
102102
NPM_CONFIG_PROVENANCE: true

apps/api/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "api",
3-
"version": "1.2.0-canary.60",
3+
"version": "1.2.0-canary.68",
44
"private": true,
55
"type": "module",
66
"scripts": {
@@ -19,20 +19,21 @@
1919
"@vitnode/core": "workspace:*",
2020
"drizzle-kit": "^0.31.6",
2121
"drizzle-orm": "^0.44.7",
22-
"hono": "^4.10.4",
23-
"next-intl": "^4.5.0",
22+
"hono": "^4.10.5",
23+
"next-intl": "^4.5.1",
2424
"react": "^19.2.0",
2525
"react-dom": "^19.2.0",
26-
"use-intl": "^4.5.0",
26+
"use-intl": "^4.5.1",
2727
"zod": "^4.1.12"
2828
},
2929
"devDependencies": {
3030
"@hono/node-server": "^1.19.6",
3131
"@react-email/components": "^1.0.0",
3232
"@types/node": "^24.10.0",
33-
"@types/react": "^19.2.2",
33+
"@types/react": "^19.2.3",
3434
"@types/react-dom": "^19.2.2",
3535
"@vitnode/config": "workspace:*",
36+
"@vitnode/nodemailer": "workspace:*",
3637
"dotenv": "^17.2.3",
3738
"eslint": "^9.39.1",
3839
"react-email": "^5.0.1",

apps/api/src/vitnode.api.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { NodemailerEmailAdapter } from "@vitnode/core/api/adapters/email/nodemailer";
21
import { buildApiConfig } from "@vitnode/core/vitnode.config";
2+
import { NodemailerEmailAdapter } from "@vitnode/nodemailer";
33
import { config } from "dotenv";
44
import { drizzle } from "drizzle-orm/postgres-js";
55

42.9 KB
Loading
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
title: Custom Adapter
3+
description: Create your own custom captcha adapter for VitNode.
4+
---
5+
6+
If you want to use captcha in your custom form or somewhere else, follow these steps.
7+
8+
## Usage
9+
10+
<Steps>
11+
<Step>
12+
13+
### Activate captcha in route
14+
15+
```ts title="plugins/{plugin_name}/src/routes/example.ts"
16+
import { buildRoute } from "@vitnode/core/api/lib/route";
17+
18+
export const exampleRoute = buildRoute({
19+
pluginId: CONFIG_PLUGIN.pluginId,
20+
route: {
21+
method: "post",
22+
description: "Create a new user",
23+
path: "/sign_up",
24+
withCaptcha: true, // [!code ++]
25+
},
26+
handler: async c => {},
27+
});
28+
```
29+
30+
</Step>
31+
<Step>
32+
33+
### Get config from middleware API
34+
35+
```tsx title="plugins/{plugin_name}/src/app/sing_up/page.tsx"
36+
import { getMiddlewareApi } from "@vitnode/core/lib/api/get-middleware-api"; // [!code ++]
37+
38+
export const SignUpView = async () => {
39+
const { captcha } = await getMiddlewareApi(); // [!code ++]
40+
41+
return <FormSignUp captcha={captcha} />;
42+
};
43+
```
44+
45+
</Step>
46+
<Step>
47+
48+
### Use `useCaptcha` hook
49+
50+
Inside your client component, use the `useCaptcha` hook to handle captcha rendering and validation. Remember to add `div` with `id="vitnode_captcha"` where you want the captcha widget to appear.
51+
52+
```tsx title="plugins/{plugin_name}/src/components/form/sign-up/sign-up.tsx"
53+
"use client";
54+
55+
import { AutoForm } from "@vitnode/core/components/form/auto-form";
56+
57+
export const FormSignUp = ({
58+
captcha, // [!code ++]
59+
}: {
60+
captcha: z.infer<typeof routeMiddlewareSchema>["captcha"]; // [!code ++]
61+
}) => {
62+
// [!code ++]
63+
const { isReady, getToken, onReset } = useCaptcha(captcha);
64+
65+
const onSubmit = async () => {
66+
await mutationApi({
67+
// ...other values,
68+
captchaToken: await getToken(), // [!code ++]
69+
});
70+
71+
// Handle success or error
72+
// [!code ++]
73+
onReset(); // Reset captcha after submission
74+
};
75+
76+
return (
77+
<form onSubmit={onSubmit}>
78+
{/* Render captcha widget */}
79+
{/* [!code ++] */}
80+
<div id="vitnode_captcha" />
81+
82+
<Button disabled={!isReady}>Submit</Button>
83+
</form>
84+
);
85+
};
86+
```
87+
88+
</Step>
89+
<Step>
90+
91+
### Submit form with captcha
92+
93+
```tsx title="plugins/{plugin_name}/src/components/form/sign-up/mutation-api.ts"
94+
"use server";
95+
96+
import type { z } from "zod";
97+
98+
import { fetcher } from "@vitnode/core/lib/fetcher";
99+
100+
export const mutationApi = async ({
101+
captchaToken, // [!code ++]
102+
}: {
103+
// [!code ++]
104+
captchaToken;
105+
}) => {
106+
await fetcher(usersModule, {
107+
path: "/test",
108+
method: "post",
109+
module: "blog",
110+
captchaToken, // [!code ++]
111+
});
112+
};
113+
```
114+
115+
</Step>
116+
</Steps>

apps/docs/content/docs/dev/captcha/index.mdx

Lines changed: 21 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ title: Captcha
33
description: Protect your forms and API call with captcha validation.
44
---
55

6-
## Support
6+
import captchaPreview from "./captcha_preview.png";
7+
8+
import { ImgDocs } from "@/components/fumadocs/img";
9+
10+
<ImgDocs src={captchaPreview} alt="Captcha Preview" />
11+
12+
## Providers
713

814
VitNode supports multiple captcha providers. You can choose the one that fits your needs. Currently, we support:
915

@@ -13,7 +19,11 @@ VitNode supports multiple captcha providers. You can choose the one that fits yo
1319
description="By Cloudflare"
1420
href="/docs/guides/captcha/cloudflare"
1521
/>
16-
<Card title="reCAPTCHA v3" description="By Google" href="/docs/guides/captcha/recaptcha" />
22+
<Card
23+
title="reCAPTCHA v3"
24+
description="By Google"
25+
href="/docs/guides/captcha/recaptcha"
26+
/>
1727
</Cards>
1828

1929
If you need more providers, feel free to open a **Feature Request** on our [GitHub repository](https://github.com/aXenDeveloper/vitnode/issues) :)
@@ -38,9 +48,9 @@ export const exampleRoute = buildRoute({
3848
method: "post",
3949
description: "Create a new user",
4050
path: "/sign_up",
41-
withCaptcha: true // [!code ++]
51+
withCaptcha: true, // [!code ++]
4252
},
43-
handler: async (c) => {}
53+
handler: async c => {},
4454
});
4555
```
4656

@@ -74,7 +84,7 @@ Get the `captcha` config from the props and pass it to the `AutoForm` component.
7484
import { AutoForm } from "@vitnode/core/components/form/auto-form";
7585

7686
export const FormSignUp = ({
77-
captcha // [!code ++]
87+
captcha, // [!code ++]
7888
}: {
7989
captcha: z.infer<typeof routeMiddlewareSchema>["captcha"]; // [!code ++]
8090
}) => {
@@ -106,23 +116,23 @@ In your form submission handler, you can get the `captchaToken` from the form su
106116

107117
import {
108118
AutoForm,
109-
type AutoFormOnSubmit // [!code ++]
119+
type AutoFormOnSubmit, // [!code ++]
110120
} from "@vitnode/core/components/form/auto-form";
111121

112122
export const FormSignUp = ({
113-
captcha
123+
captcha,
114124
}: {
115125
captcha: z.infer<typeof routeMiddlewareSchema>["captcha"];
116126
}) => {
117127
const onSubmit: AutoFormOnSubmit<typeof formSchema> = async (
118128
values,
119129
form,
120-
{ captchaToken } // [!code ++]
130+
{ captchaToken }, // [!code ++]
121131
) => {
122132
// Call your mutation API with captcha token
123133
await mutationApi({
124134
...values,
125-
captchaToken // [!code ++]
135+
captchaToken, // [!code ++]
126136
});
127137

128138
// Handle success or error
@@ -159,8 +169,8 @@ z.infer<typeof zodSignUpSchema> & { captchaToken: string }) => {
159169
module: "users",
160170
captchaToken, // [!code ++]
161171
args: {
162-
body: input
163-
}
172+
body: input,
173+
},
164174
});
165175

166176
if (res.status !== 201) {
@@ -175,115 +185,3 @@ z.infer<typeof zodSignUpSchema> & { captchaToken: string }) => {
175185

176186
</Step>
177187
</Steps>
178-
179-
## Custom Usage
180-
181-
If you want to use captcha in your custom form or somewhere else, follow these steps.
182-
183-
<Steps>
184-
<Step>
185-
186-
### Activate captcha in route
187-
188-
```ts title="plugins/{plugin_name}/src/routes/example.ts"
189-
import { buildRoute } from "@vitnode/core/api/lib/route";
190-
191-
export const exampleRoute = buildRoute({
192-
pluginId: CONFIG_PLUGIN.pluginId,
193-
route: {
194-
method: "post",
195-
description: "Create a new user",
196-
path: "/sign_up",
197-
withCaptcha: true // [!code ++]
198-
},
199-
handler: async (c) => {}
200-
});
201-
```
202-
203-
</Step>
204-
<Step>
205-
206-
### Get config from middleware API
207-
208-
```tsx title="plugins/{plugin_name}/src/app/sing_up/page.tsx"
209-
import { getMiddlewareApi } from "@vitnode/core/lib/api/get-middleware-api"; // [!code ++]
210-
211-
export const SignUpView = async () => {
212-
const { captcha } = await getMiddlewareApi(); // [!code ++]
213-
214-
return <FormSignUp captcha={captcha} />;
215-
};
216-
```
217-
218-
</Step>
219-
<Step>
220-
221-
### Use `useCaptcha` hook
222-
223-
Inside your client component, use the `useCaptcha` hook to handle captcha rendering and validation. Remember to add `div` with `id="vitnode_captcha"` where you want the captcha widget to appear.
224-
225-
```tsx title="plugins/{plugin_name}/src/components/form/sign-up/sign-up.tsx"
226-
"use client";
227-
228-
import { AutoForm } from "@vitnode/core/components/form/auto-form";
229-
230-
export const FormSignUp = ({
231-
captcha // [!code ++]
232-
}: {
233-
captcha: z.infer<typeof routeMiddlewareSchema>["captcha"]; // [!code ++]
234-
}) => {
235-
// [!code ++]
236-
const { isReady, getToken, onReset } = useCaptcha(captcha);
237-
238-
const onSubmit = async () => {
239-
await mutationApi({
240-
// ...other values,
241-
captchaToken: await getToken() // [!code ++]
242-
});
243-
244-
// Handle success or error
245-
// [!code ++]
246-
onReset(); // Reset captcha after submission
247-
};
248-
249-
return (
250-
<form onSubmit={onSubmit}>
251-
{/* Render captcha widget */}
252-
{/* [!code ++] */}
253-
<div id="vitnode_captcha" />
254-
255-
<Button disabled={!isReady}>Submit</Button>
256-
</form>
257-
);
258-
};
259-
```
260-
261-
</Step>
262-
<Step>
263-
264-
### Submit form with captcha
265-
266-
```tsx title="plugins/{plugin_name}/src/components/form/sign-up/mutation-api.ts"
267-
"use server";
268-
269-
import type { z } from "zod";
270-
271-
import { fetcher } from "@vitnode/core/lib/fetcher";
272-
273-
export const mutationApi = async ({
274-
captchaToken // [!code ++]
275-
}: {
276-
// [!code ++]
277-
captchaToken;
278-
}) => {
279-
await fetcher(usersModule, {
280-
path: "/test",
281-
method: "post",
282-
module: "blog",
283-
captchaToken // [!code ++]
284-
});
285-
};
286-
```
287-
288-
</Step>
289-
</Steps>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"title": "Captcha",
3+
"pages": ["...", "custom-adapter"]
4+
}

0 commit comments

Comments
 (0)