{
const hono = new OpenAPIHono();
@@ -58,5 +61,5 @@ export function buildModule<
});
}
- return { routes, pluginId, hono, name, modules };
+ return { routes, pluginId, hono, name, modules, cronJobs };
}
diff --git a/packages/vitnode/src/api/lib/plugin.ts b/packages/vitnode/src/api/lib/plugin.ts
index f4829a34d..8d495dcc6 100644
--- a/packages/vitnode/src/api/lib/plugin.ts
+++ b/packages/vitnode/src/api/lib/plugin.ts
@@ -1,10 +1,12 @@
import { OpenAPIHono } from "@hono/zod-openapi";
import { checkPluginId } from "./check-plugin-id";
+import type { CronJobConfig } from "./cron";
import type { BuildModuleReturn } from "./module";
export interface BuildPluginApiReturn {
hono: OpenAPIHono;
pluginId: string;
+ cronJobs: Omit ({
@@ -18,12 +20,18 @@ export function buildApiPlugin ({
checkPluginId(pluginId);
const hono = new OpenAPIHono();
+ const cronJobs: BuildPluginApiReturn["cronJobs"] = [];
modules.forEach(handler => {
hono.route(`/${handler.name}`, handler.hono);
+
+ handler.cronJobs?.forEach(cron => {
+ cronJobs.push({ ...cron, module: handler.name });
+ });
});
return {
pluginId,
hono,
+ cronJobs,
};
}
diff --git a/packages/vitnode/src/api/middlewares/cron-auth.middleware.ts b/packages/vitnode/src/api/middlewares/cron-auth.middleware.ts
new file mode 100644
index 000000000..8a098842b
--- /dev/null
+++ b/packages/vitnode/src/api/middlewares/cron-auth.middleware.ts
@@ -0,0 +1,20 @@
+import type { Context, Next } from "hono";
+import { HTTPException } from "hono/http-exception";
+
+export const cronAuthMiddleware = () => {
+ return async (c: Context, next: Next) => {
+ const cronSecret = c.get("core").cronSecret;
+ if (!cronSecret) {
+ throw new HTTPException(403, { message: "Cron access not configured" });
+ }
+
+ const authHeader = c.req.header("authorization");
+ const providedSecret = authHeader?.replace("Bearer ", "");
+
+ if (providedSecret !== cronSecret) {
+ throw new HTTPException(403, { message: "Invalid cron authorization" });
+ }
+
+ await next();
+ };
+};
diff --git a/packages/vitnode/src/api/middlewares/global.middleware.ts b/packages/vitnode/src/api/middlewares/global.middleware.ts
index ec8bf40a1..0fecf6a3e 100644
--- a/packages/vitnode/src/api/middlewares/global.middleware.ts
+++ b/packages/vitnode/src/api/middlewares/global.middleware.ts
@@ -4,7 +4,9 @@ import { HTTPException } from "hono/http-exception";
import { EmailModel, type EmailModelSendArgs } from "@/api/models/email";
import { SessionModel } from "@/api/models/session";
import { SessionAdminModel } from "@/api/models/session-admin";
+import { CONFIG } from "@/lib/config";
import type { VitNodeApiConfig, VitNodeConfig } from "@/vitnode.config";
+import type { BuildCronReturn } from "../lib/cron";
import {
type LoggerMiddlewareType,
loggerMiddleware,
@@ -46,6 +48,7 @@ export interface EnvVariablesVitNode {
ssoAdapters: SSOApiPlugin[];
};
captcha?: Pick {row.description}[role=checkbox]]:translate-y-[2px]",
+ "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className,
)}
data-slot="table-cell"
diff --git a/packages/vitnode/src/components/ui/tooltip.tsx b/packages/vitnode/src/components/ui/tooltip.tsx
index 6a22d0947..4be9a7ae2 100644
--- a/packages/vitnode/src/components/ui/tooltip.tsx
+++ b/packages/vitnode/src/components/ui/tooltip.tsx
@@ -6,7 +6,7 @@ import type * as React from "react";
import { cn } from "@/lib/utils";
function TooltipProvider({
- delayDuration = 500,
+ delayDuration = 200,
...props
}: React.ComponentProps