Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/docs/content/docs/plugins/blog.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: Blog
description: xx
icon: House
---
22 changes: 22 additions & 0 deletions apps/docs/content/docs/plugins/create.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: Get Started
description: xx
---

import { Tab, Tabs } from 'fumadocs-ui/components/tabs';

<Tabs groupId='package-manager' persist items={['pnpm', 'npm', 'bun']} label='Create a Plugin'>

```bash tab="pnpm"
pnpm create vitnode-app@canary --plugin
```

```bash tab="npm"
npx create-vitnode-app@canary --plugin
```

```bash tab="bun"
bun create vitnode-app@canary --plugin
```

</Tabs>
20 changes: 1 addition & 19 deletions apps/docs/content/docs/plugins/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,4 @@ description: Create awesome plugins for VitNode.
icon: House
---

## Create a Plugin

import { Tab, Tabs } from 'fumadocs-ui/components/tabs';

<Tabs groupId='package-manager' persist items={['pnpm', 'npm', 'bun']} label='Create a Plugin'>

```bash tab="pnpm"
pnpm create vitnode-app@canary --plugin
```

```bash tab="npm"
npx create-vitnode-app@canary --plugin
```

```bash tab="bun"
bun create vitnode-app@canary --plugin
```

</Tabs>
test
2 changes: 1 addition & 1 deletion apps/docs/content/docs/plugins/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"description": "Create and share own plugins",
"icon": "Plug",
"root": true,
"pages": ["index", "..."]
"pages": ["index", "---Plugins---", "blog", "---Custom Plugin---", "..."]
}
36 changes: 3 additions & 33 deletions apps/web/src/app/api/[...route]/route.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,14 @@
import { vitNodeApiConfig } from '@/vitnode.api.config';
import { vitNodeConfig } from '@/vitnode.config';
import { OpenAPIHono } from '@hono/zod-openapi';
import { handle } from 'hono/vercel';
import { VitNodeAPI } from 'vitnode/api/config';
import { NodemailerEmailPlugin } from 'vitnode/api/plugins/email/nodemailer';
// import { ResendEmailPlugin } from 'vitnode/api/plugins/email/resend';
import { DiscordSSOApiPlugin } from 'vitnode/api/plugins/sso/discord';
import { FacebookSSOApiPlugin } from 'vitnode/api/plugins/sso/facebook';
import { GoogleSSOApiPlugin } from 'vitnode/api/plugins/sso/google';

const app = new OpenAPIHono().basePath('/api');
VitNodeAPI({
app,
plugins: vitNodeConfig.plugins,
metadata: vitNodeConfig.metadata,
// emailProvider: ResendEmailPlugin({
// apiKey: process.env.RESEND_API_KEY ?? '',
// from: process.env.RESEND_FROM ?? '',
// }),
emailProvider: NodemailerEmailPlugin({
from: process.env.NODE_MAILER_FROM,
host: process.env.NODE_MAILER_HOST,
password: process.env.NODE_MAILER_PASSWORD,
user: process.env.NOD_EMAILER_USER,
}),
authorization: {
ssoPlugins: [
DiscordSSOApiPlugin({
clientId: process.env.DISCORD_CLIENT_ID,
clientSecret: process.env.DISCORD_CLIENT_SECRET,
}),
GoogleSSOApiPlugin({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
FacebookSSOApiPlugin({
clientId: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
}),
],
},
vitNodeApiConfig,
vitNodeConfig,
});

export const GET = handle(app);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ CREATE TABLE "core_languages" (
"enabled" boolean DEFAULT true NOT NULL,
"createdAt" timestamp DEFAULT now() NOT NULL,
"updatedAt" timestamp NOT NULL,
"time_24" boolean DEFAULT false NOT NULL,
"allow_in_input" boolean DEFAULT true NOT NULL,
"time24" boolean DEFAULT false NOT NULL,
CONSTRAINT "core_languages_code_unique" UNIQUE("code")
);
--> statement-breakpoint
Expand Down
13 changes: 3 additions & 10 deletions apps/web/src/database/migrations/meta/0000_snapshot.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"id": "95791a90-7337-433f-9510-8d6f9e4125ff",
"id": "fd378528-22f1-4e30-9108-4e06020776ba",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
Expand Down Expand Up @@ -299,19 +299,12 @@
"primaryKey": false,
"notNull": true
},
"time_24": {
"name": "time_24",
"time24": {
"name": "time24",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"allow_in_input": {
"name": "allow_in_input",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
}
},
"indexes": {
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/database/migrations/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
{
"idx": 0,
"version": "7",
"when": 1746105704858,
"tag": "0000_hesitant_sumo",
"when": 1747245244787,
"tag": "0000_funny_korath",
"breakpoints": true
}
]
Expand Down
3 changes: 1 addition & 2 deletions apps/web/src/database/schema/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ export const core_languages = pgTable(
.timestamp()
.notNull()
.$onUpdate(() => new Date()),
time_24: t.boolean().notNull().default(false),
allow_in_input: t.boolean().default(true).notNull(),
time24: t.boolean().notNull().default(false),
}),
t => [
index('core_languages_code_idx').on(t.code),
Expand Down
32 changes: 32 additions & 0 deletions apps/web/src/vitnode.api.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { blogApiPlugin } from 'vitnode-blog/api';
import { NodemailerEmailPlugin } from 'vitnode/api/plugins/email/nodemailer';
import { DiscordSSOApiPlugin } from 'vitnode/api/plugins/sso/discord';
import { FacebookSSOApiPlugin } from 'vitnode/api/plugins/sso/facebook';
import { GoogleSSOApiPlugin } from 'vitnode/api/plugins/sso/google';
import { buildApiConfig } from 'vitnode/vitnode.config';

export const vitNodeApiConfig = buildApiConfig({
plugins: [blogApiPlugin()],
emailProvider: NodemailerEmailPlugin({
from: process.env.NODE_MAILER_FROM,
host: process.env.NODE_MAILER_HOST,
password: process.env.NODE_MAILER_PASSWORD,
user: process.env.NOD_EMAILER_USER,
}),
authorization: {
ssoPlugins: [
DiscordSSOApiPlugin({
clientId: process.env.DISCORD_CLIENT_ID,
clientSecret: process.env.DISCORD_CLIENT_SECRET,
}),
GoogleSSOApiPlugin({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
FacebookSSOApiPlugin({
clientId: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
}),
],
},
});
8 changes: 4 additions & 4 deletions apps/web/src/vitnode.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getRequestConfig } from 'next-intl/server';
import { blogPlugin } from 'vitnode-blog/plugin.config';
import { blogPlugin } from 'vitnode-blog/plugin';
import { buildConfig, handleRequestConfig } from 'vitnode/vitnode.config';

export const vitNodeConfig = buildConfig({
Expand All @@ -19,6 +19,6 @@ export const vitNodeConfig = buildConfig({
});

// This is the request config for the app. It will be used in the app router.
export default getRequestConfig(async ({ requestLocale }) =>
handleRequestConfig({ requestLocale, vitNodeConfig }),
);
export default getRequestConfig(async ({ requestLocale }) => {
return await handleRequestConfig({ requestLocale, vitNodeConfig });
});
25 changes: 16 additions & 9 deletions packages/vitnode/src/api/config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { VitNodeApiConfig, VitNodeConfig } from '@/vitnode.config';
import type { OpenAPIHono } from '@hono/zod-openapi';
import type { Context, Env, Schema } from 'hono';

import { newBuildPluginCore } from '@/api/plugin';
import { newBuildPluginApiCore } from '@/api/plugin';
import { swaggerUI } from '@hono/swagger-ui';
import { cors } from 'hono/cors';
import { csrf } from 'hono/csrf';
import { HTTPException } from 'hono/http-exception';

import type { BuildPluginReturn } from '../lib/plugin';

import { internalVitNodeConfig } from './internal-config';
import {
globalAdminMiddleware,
Expand Down Expand Up @@ -36,13 +35,14 @@ export function VitNodeAPI({
app,
cors: corsOptions,
csrf: csrfOptions,
plugins,
...options
}: Parameters<typeof globalMiddleware>[0] & {
vitNodeApiConfig,
vitNodeConfig,
}: {
app: OpenAPIHono<Env, Schema, string>;
cors?: CORSOptions;
csrf?: CSRFOptions;
plugins: BuildPluginReturn[];
vitNodeApiConfig: VitNodeApiConfig;
vitNodeConfig: VitNodeConfig;
}) {
app.doc('/swagger/doc', {
openapi: '3.0.0',
Expand All @@ -54,7 +54,14 @@ export function VitNodeAPI({
app.use(cors(corsOptions));
app.use(csrf(csrfOptions));
app.get('/swagger', swaggerUI({ url: `/api/swagger/doc` }));
app.use('*', globalMiddleware(options));
app.use(
'*',
globalMiddleware({
emailProvider: vitNodeApiConfig.emailProvider,
metadata: vitNodeConfig.metadata,
authorization: vitNodeApiConfig.authorization,
}),
);
app.use('/*/admin/*', globalAdminMiddleware());

app.onError(error => {
Expand All @@ -75,7 +82,7 @@ export function VitNodeAPI({
);
});

[newBuildPluginCore, ...plugins].map(root => {
[newBuildPluginApiCore, ...vitNodeApiConfig.plugins].map(root => {
app.route(`/${root.name}`, root.hono);
});

Expand Down
23 changes: 23 additions & 0 deletions packages/vitnode/src/api/lib/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { OpenAPIHono } from '@hono/zod-openapi';

import type { BuildModuleReturn } from './module';

export interface BuildPluginApiReturn {
hono: OpenAPIHono;
name: string;
}

export function buildApiPlugin<P extends string>({
name,
modules = [],
}: {
modules?: BuildModuleReturn<P, string>[];
name: P;
}): BuildPluginApiReturn {
const hono = new OpenAPIHono();
modules.forEach(handler => {
hono.route(`/${handler.name}`, handler.hono);
});

return { name, hono };
}
20 changes: 3 additions & 17 deletions packages/vitnode/src/api/middlewares/global/global.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { EmailApiPlugin } from '@/api/models/email';
import type { VitNodeApiConfig, VitNodeConfig } from '@/vitnode.config';
import type { Context, Env, Next } from 'hono';

import { DeviceModel } from '@/api/models/device';
Expand Down Expand Up @@ -61,23 +62,8 @@ export const globalMiddleware = ({
authorization,
metadata,
emailProvider,
}: {
authorization?: {
adminCookieExpires?: number;
adminCookieName?: string;
cookieExpires?: number;
cookieName?: string;
cookieSecure?: boolean;
deviceCookieExpires?: number;
deviceCookieName?: string;
ssoPlugins?: SSOApiPlugin[];
};
emailProvider?: EmailApiPlugin;
metadata: {
shortTitle?: string;
title: string;
};
}) => {
}: Pick<VitNodeApiConfig, 'authorization' | 'emailProvider'> &
Pick<VitNodeConfig, 'metadata'>) => {
return async (c: Context<Env, '*'>, next: Next) => {
c.set('core', {
metadata,
Expand Down
4 changes: 2 additions & 2 deletions packages/vitnode/src/api/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { buildPlugin } from '../lib/plugin';
import { buildApiPlugin } from './lib/plugin';
import { adminModule } from './modules/admin/admin.module';
import { middlewareModule } from './modules/middleware/middleware.module';
import { usersModule } from './modules/users/users.module';

export const newBuildPluginCore = buildPlugin({
export const newBuildPluginApiCore = buildApiPlugin({
name: 'core',
modules: [middlewareModule, usersModule, adminModule],
});
3 changes: 1 addition & 2 deletions packages/vitnode/src/database/schema/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ export const core_languages = pgTable(
.timestamp()
.notNull()
.$onUpdate(() => new Date()),
time_24: t.boolean().notNull().default(false),
allow_in_input: t.boolean().default(true).notNull(),
time24: t.boolean().notNull().default(false),
}),
t => [
index('core_languages_code_idx').on(t.code),
Expand Down
24 changes: 6 additions & 18 deletions packages/vitnode/src/lib/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
import { OpenAPIHono } from '@hono/zod-openapi';

import type { BuildModuleReturn } from '../api/lib/module';

export interface BuildPluginReturn {
hono: OpenAPIHono;
name: string;
export interface BuildPluginReturn<P extends string = string> {
name: P;
pages?: () => React.ReactNode;
}

export function buildPlugin<P extends string>({
name,
modules = [],
}: {
modules?: BuildModuleReturn<P, string>[];
name: P;
}): BuildPluginReturn {
const hono = new OpenAPIHono();
modules.forEach(handler => {
hono.route(`/${handler.name}`, handler.hono);
});

return { name, hono };
pages,
}: BuildPluginReturn<P>): BuildPluginReturn<P> {
return { name, pages };
}
Loading
Loading