diff --git a/.github/docs/prd.md b/.github/docs/prd.md
index 7962b96e1..2fa4f21ae 100644
--- a/.github/docs/prd.md
+++ b/.github/docs/prd.md
@@ -120,6 +120,9 @@ VitNode is designed for individual developers and small teams who need a structu
- Component scaffolding
- API endpoint generation
- Database schema generation from models
+- Logging system with structured logs:
+ - Log levels (debug, info, warn, error)
+ - Contextual logging with request/response metadata
### File Management
diff --git a/apps/docs/content/docs/dev/config/rate-limiter.mdx b/apps/docs/content/docs/dev/config/rate-limiter.mdx
index 696da72c7..830bef896 100644
--- a/apps/docs/content/docs/dev/config/rate-limiter.mdx
+++ b/apps/docs/content/docs/dev/config/rate-limiter.mdx
@@ -27,7 +27,7 @@ import { TypeTable } from 'fumadocs-ui/components/type-table';
description:
'The number of requests allowed within the specified duration.',
type: 'number',
- default: '40',
+ default: '80 (120 in dev)',
},
duration: {
description:
diff --git a/apps/docs/content/docs/dev/database/pagination.mdx b/apps/docs/content/docs/dev/database/pagination.mdx
index b2cac5767..fad97a68b 100644
--- a/apps/docs/content/docs/dev/database/pagination.mdx
+++ b/apps/docs/content/docs/dev/database/pagination.mdx
@@ -127,18 +127,13 @@ On the frontend, the pagination system works seamlessly with the DataTable compo
When fetching data from the API, include the pagination parameters in your request:
```tsx
+const query = await searchParams; // Assume searchParams is a Promise from the Next.js page context
const res = await fetcher(userModule, {
path: '/users',
method: 'get',
module: 'user',
args: {
- query: {
- cursor: searchParams.cursor,
- first: searchParams.first,
- last: searchParams.last,
- order: searchParams.order,
- orderBy: searchParams.orderBy,
- },
+ query,
},
withPagination: true, // Important flag for pagination
});
diff --git a/apps/docs/content/docs/dev/fetcher.mdx b/apps/docs/content/docs/dev/fetcher.mdx
index 22395ef94..17f733da2 100644
--- a/apps/docs/content/docs/dev/fetcher.mdx
+++ b/apps/docs/content/docs/dev/fetcher.mdx
@@ -39,6 +39,28 @@ The fetcher returns a standard Response object, just like the native `fetch` API
## Advanced Features
+### Path Prefixing
+
+When working with nested modules you can import the module and use it directly with the `fetcher` function and add the `prefixPath` option to specify a path prefix. This is useful for organizing your API endpoints and keeping them modular.
+
+```ts
+const response = await fetcher(categoriesAdminModule, {
+ // [!code ++]
+ prefixPath: '/admin', // Adds prefix to the path
+ path: '/categories',
+ method: 'post',
+ module: 'categories',
+ args: {
+ body: {
+ name: 'Technology',
+ description: 'Tech-related articles',
+ },
+ },
+});
+
+// This will make a request to: /admin/categories
+```
+
### Caching Responses
You can leverage Next.js caching by passing cache options:
diff --git a/apps/docs/content/docs/dev/logging.mdx b/apps/docs/content/docs/dev/logging.mdx
index 63e1bc067..93885237a 100644
--- a/apps/docs/content/docs/dev/logging.mdx
+++ b/apps/docs/content/docs/dev/logging.mdx
@@ -1,4 +1,47 @@
---
title: Logging
-description: Centralized logging with VitNode
+description: Structured logging system for VitNode applications
---
+
+VitNode provides a logging system that allows you to log messages at different levels _(debug, warn, error)_ with structured logs. This is useful for debugging and monitoring your application.
+
+All logs are stored in your database. You can view them in the `Debug Panel`.
+
+## Usage
+
+```ts
+import { buildRoute } from '@vitnode/core/api/lib/route';
+```
+
+```ts
+export const testRoute = buildRoute(
+ {},
+ {
+ handler: c => {
+ c.get('log').warn('This is a test warn log'); // [!code ++]
+
+ return c.text('test');
+ },
+ },
+);
+```
+
+### Variants
+
+import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
+
+
+
+```ts tab="Debug"
+c.get('log').debug('This is a test debug log');
+```
+
+```ts tab="Warn"
+c.get('log').warn('This is a test warning log');
+```
+
+```ts tab="Error"
+c.get('log').error('This is a test error log');
+```
+
+
diff --git a/apps/docs/src/app/global.css b/apps/docs/src/app/global.css
index 267bc9998..96cd4e75e 100644
--- a/apps/docs/src/app/global.css
+++ b/apps/docs/src/app/global.css
@@ -20,8 +20,8 @@
--muted-foreground: oklch(0.45 0 0);
--accent: oklch(0.95 0 0);
--accent-foreground: oklch(0.205 0 0);
- --destructive: oklch(0.577 0.245 27.325);
- --destructive-foreground: oklch(0.577 0.245 27.325);
+ --destructive: oklch(0.6 0.2 24.45);
+ --warn: oklch(0.57 0.13 82.37);
--border: oklch(0.9 0 0);
--input: oklch(0.9 0 0);
--ring: oklch(0.7 0.16 262.61);
@@ -58,8 +58,8 @@
--muted: oklch(0.22 0 0);
--muted-foreground: oklch(0.7 0 0);
--accent: oklch(0.28 0 0);
- --destructive: oklch(0.704 0.191 22.216);
- --destructive-foreground: oklch(0.704 0.191 22.216);
+ --destructive: oklch(0.62 0.2 25.35);
+ --warn: oklch(0.76 0.18 81.84);
--border: oklch(0.28 0 0);
--input: oklch(0.28 0 0);
--ring: oklch(0.51 0.16 262.61);
@@ -102,7 +102,7 @@
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
- --color-destructive-foreground: var(--destructive-foreground);
+ --color-warn: var(--warn);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
diff --git a/apps/web/migrations/0000_overjoyed_sandman.sql b/apps/web/migrations/0000_stormy_ronan.sql
similarity index 95%
rename from apps/web/migrations/0000_overjoyed_sandman.sql
rename to apps/web/migrations/0000_stormy_ronan.sql
index 1a58e8ea3..f2c645079 100644
--- a/apps/web/migrations/0000_overjoyed_sandman.sql
+++ b/apps/web/migrations/0000_stormy_ronan.sql
@@ -1,3 +1,4 @@
+CREATE TYPE "public"."coreLogsType" AS ENUM('warn', 'error', 'debug');--> statement-breakpoint
CREATE TABLE "core_admin_permissions" (
"id" serial PRIMARY KEY NOT NULL,
"roleId" integer,
@@ -46,6 +47,16 @@ CREATE TABLE "core_languages_words" (
);
--> statement-breakpoint
ALTER TABLE "core_languages_words" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
+CREATE TABLE "core_logs" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "pluginId" varchar(255) NOT NULL,
+ "type" "coreLogsType" NOT NULL,
+ "content" text NOT NULL,
+ "createdAt" timestamp DEFAULT now() NOT NULL,
+ "ipAddress" varchar(45) NOT NULL
+);
+--> statement-breakpoint
+ALTER TABLE "core_logs" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
CREATE TABLE "core_moderators_permissions" (
"id" serial PRIMARY KEY NOT NULL,
"roleId" integer,
@@ -81,9 +92,11 @@ CREATE TABLE "core_sessions" (
ALTER TABLE "core_sessions" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
CREATE TABLE "core_sessions_known_devices" (
"id" serial PRIMARY KEY NOT NULL,
+ "publicId" varchar(32) NOT NULL,
"ipAddress" varchar(40) NOT NULL,
"userAgent" text NOT NULL,
- "lastSeen" timestamp DEFAULT now() NOT NULL
+ "lastSeen" timestamp DEFAULT now() NOT NULL,
+ CONSTRAINT "core_sessions_known_devices_publicId_unique" UNIQUE("publicId")
);
--> statement-breakpoint
ALTER TABLE "core_sessions_known_devices" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
diff --git a/apps/web/migrations/0001_mute_flatman.sql b/apps/web/migrations/0001_mute_flatman.sql
deleted file mode 100644
index d2de99678..000000000
--- a/apps/web/migrations/0001_mute_flatman.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE "core_sessions_known_devices" ADD COLUMN "publicId" varchar(32) NOT NULL;--> statement-breakpoint
-ALTER TABLE "core_sessions_known_devices" ADD CONSTRAINT "core_sessions_known_devices_publicId_unique" UNIQUE("publicId");
\ No newline at end of file
diff --git a/apps/web/migrations/0002_superb_natasha_romanoff.sql b/apps/web/migrations/0002_superb_natasha_romanoff.sql
deleted file mode 100644
index 665631ad9..000000000
--- a/apps/web/migrations/0002_superb_natasha_romanoff.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-CREATE TYPE "public"."typeLogs" AS ENUM('info', 'warn', 'error', 'debug');--> statement-breakpoint
-CREATE TABLE "core_logs" (
- "id" serial PRIMARY KEY NOT NULL,
- "pluginCode" varchar(255) NOT NULL,
- "type" "typeLogs" DEFAULT 'info' NOT NULL,
- "content" text NOT NULL,
- "createdAt" timestamp DEFAULT now() NOT NULL,
- "userId" integer,
- "ipAddress" varchar(45) DEFAULT '' NOT NULL
-);
---> statement-breakpoint
-ALTER TABLE "core_logs" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
-ALTER TABLE "core_logs" ADD CONSTRAINT "core_logs_userId_core_users_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."core_users"("id") ON DELETE set null ON UPDATE no action;
\ No newline at end of file
diff --git a/apps/web/migrations/meta/0000_snapshot.json b/apps/web/migrations/meta/0000_snapshot.json
index bcd213c2a..0b46f9572 100644
--- a/apps/web/migrations/meta/0000_snapshot.json
+++ b/apps/web/migrations/meta/0000_snapshot.json
@@ -1,5 +1,5 @@
{
- "id": "d8197fc3-2d92-4d22-9381-9ebb1412c8fc",
+ "id": "960a9871-cd4a-4144-bc0a-af0717f397a7",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
@@ -439,6 +439,57 @@
"checkConstraints": {},
"isRLSEnabled": true
},
+ "public.core_logs": {
+ "name": "core_logs",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "pluginId": {
+ "name": "pluginId",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "coreLogsType",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "content": {
+ "name": "content",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "ipAddress": {
+ "name": "ipAddress",
+ "type": "varchar(45)",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": true
+ },
"public.core_moderators_permissions": {
"name": "core_moderators_permissions",
"schema": "",
@@ -725,6 +776,12 @@
"primaryKey": true,
"notNull": true
},
+ "publicId": {
+ "name": "publicId",
+ "type": "varchar(32)",
+ "primaryKey": false,
+ "notNull": true
+ },
"ipAddress": {
"name": "ipAddress",
"type": "varchar(40)",
@@ -764,7 +821,15 @@
},
"foreignKeys": {},
"compositePrimaryKeys": {},
- "uniqueConstraints": {},
+ "uniqueConstraints": {
+ "core_sessions_known_devices_publicId_unique": {
+ "name": "core_sessions_known_devices_publicId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "publicId"
+ ]
+ }
+ },
"policies": {},
"checkConstraints": {},
"isRLSEnabled": true
@@ -1310,7 +1375,17 @@
"isRLSEnabled": true
}
},
- "enums": {},
+ "enums": {
+ "public.coreLogsType": {
+ "name": "coreLogsType",
+ "schema": "public",
+ "values": [
+ "warn",
+ "error",
+ "debug"
+ ]
+ }
+ },
"schemas": {},
"sequences": {},
"roles": {},
diff --git a/apps/web/migrations/meta/0001_snapshot.json b/apps/web/migrations/meta/0001_snapshot.json
deleted file mode 100644
index 26e4c85b4..000000000
--- a/apps/web/migrations/meta/0001_snapshot.json
+++ /dev/null
@@ -1,1338 +0,0 @@
-{
- "id": "147890d3-87ad-4e29-a83e-43b220c8af80",
- "prevId": "d8197fc3-2d92-4d22-9381-9ebb1412c8fc",
- "version": "7",
- "dialect": "postgresql",
- "tables": {
- "public.core_admin_permissions": {
- "name": "core_admin_permissions",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "roleId": {
- "name": "roleId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "protected": {
- "name": "protected",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- }
- },
- "indexes": {
- "core_admin_permissions_role_id_idx": {
- "name": "core_admin_permissions_role_id_idx",
- "columns": [
- {
- "expression": "roleId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_admin_permissions_user_id_idx": {
- "name": "core_admin_permissions_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_admin_permissions_roleId_core_roles_id_fk": {
- "name": "core_admin_permissions_roleId_core_roles_id_fk",
- "tableFrom": "core_admin_permissions",
- "tableTo": "core_roles",
- "columnsFrom": [
- "roleId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "core_admin_permissions_userId_core_users_id_fk": {
- "name": "core_admin_permissions_userId_core_users_id_fk",
- "tableFrom": "core_admin_permissions",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_admin_sessions": {
- "name": "core_admin_sessions",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "token": {
- "name": "token",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "lastSeen": {
- "name": "lastSeen",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "expiresAt": {
- "name": "expiresAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "deviceId": {
- "name": "deviceId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {
- "core_admin_sessions_token_idx": {
- "name": "core_admin_sessions_token_idx",
- "columns": [
- {
- "expression": "token",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_admin_sessions_user_id_idx": {
- "name": "core_admin_sessions_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_admin_sessions_userId_core_users_id_fk": {
- "name": "core_admin_sessions_userId_core_users_id_fk",
- "tableFrom": "core_admin_sessions",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "core_admin_sessions_deviceId_core_sessions_known_devices_id_fk": {
- "name": "core_admin_sessions_deviceId_core_sessions_known_devices_id_fk",
- "tableFrom": "core_admin_sessions",
- "tableTo": "core_sessions_known_devices",
- "columnsFrom": [
- "deviceId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_admin_sessions_token_unique": {
- "name": "core_admin_sessions_token_unique",
- "nullsNotDistinct": false,
- "columns": [
- "token"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_languages": {
- "name": "core_languages",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "code": {
- "name": "code",
- "type": "varchar(32)",
- "primaryKey": false,
- "notNull": true
- },
- "name": {
- "name": "name",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "timezone": {
- "name": "timezone",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true,
- "default": "'UTC'"
- },
- "protected": {
- "name": "protected",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "default": {
- "name": "default",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "enabled": {
- "name": "enabled",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "time24": {
- "name": "time24",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- }
- },
- "indexes": {
- "core_languages_code_idx": {
- "name": "core_languages_code_idx",
- "columns": [
- {
- "expression": "code",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_languages_name_idx": {
- "name": "core_languages_name_idx",
- "columns": [
- {
- "expression": "name",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_languages_code_unique": {
- "name": "core_languages_code_unique",
- "nullsNotDistinct": false,
- "columns": [
- "code"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_languages_words": {
- "name": "core_languages_words",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "languageCode": {
- "name": "languageCode",
- "type": "varchar",
- "primaryKey": false,
- "notNull": true
- },
- "pluginCode": {
- "name": "pluginCode",
- "type": "varchar(50)",
- "primaryKey": false,
- "notNull": true
- },
- "itemId": {
- "name": "itemId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "value": {
- "name": "value",
- "type": "text",
- "primaryKey": false,
- "notNull": true
- },
- "tableName": {
- "name": "tableName",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "variable": {
- "name": "variable",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {
- "core_languages_words_lang_code_idx": {
- "name": "core_languages_words_lang_code_idx",
- "columns": [
- {
- "expression": "languageCode",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_languages_words_languageCode_core_languages_code_fk": {
- "name": "core_languages_words_languageCode_core_languages_code_fk",
- "tableFrom": "core_languages_words",
- "tableTo": "core_languages",
- "columnsFrom": [
- "languageCode"
- ],
- "columnsTo": [
- "code"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_moderators_permissions": {
- "name": "core_moderators_permissions",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "roleId": {
- "name": "roleId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "protected": {
- "name": "protected",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- }
- },
- "indexes": {
- "core_moderators_permissions_role_id_idx": {
- "name": "core_moderators_permissions_role_id_idx",
- "columns": [
- {
- "expression": "roleId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_moderators_permissions_user_id_idx": {
- "name": "core_moderators_permissions_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_moderators_permissions_roleId_core_roles_id_fk": {
- "name": "core_moderators_permissions_roleId_core_roles_id_fk",
- "tableFrom": "core_moderators_permissions",
- "tableTo": "core_roles",
- "columnsFrom": [
- "roleId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "core_moderators_permissions_userId_core_users_id_fk": {
- "name": "core_moderators_permissions_userId_core_users_id_fk",
- "tableFrom": "core_moderators_permissions",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_roles": {
- "name": "core_roles",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "protected": {
- "name": "protected",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "default": {
- "name": "default",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "root": {
- "name": "root",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "guest": {
- "name": "guest",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "color": {
- "name": "color",
- "type": "varchar(19)",
- "primaryKey": false,
- "notNull": false
- }
- },
- "indexes": {},
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_sessions": {
- "name": "core_sessions",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "token": {
- "name": "token",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "expiresAt": {
- "name": "expiresAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "deviceId": {
- "name": "deviceId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {
- "core_sessions_user_id_idx": {
- "name": "core_sessions_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_sessions_userId_core_users_id_fk": {
- "name": "core_sessions_userId_core_users_id_fk",
- "tableFrom": "core_sessions",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "core_sessions_deviceId_core_sessions_known_devices_id_fk": {
- "name": "core_sessions_deviceId_core_sessions_known_devices_id_fk",
- "tableFrom": "core_sessions",
- "tableTo": "core_sessions_known_devices",
- "columnsFrom": [
- "deviceId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_sessions_token_unique": {
- "name": "core_sessions_token_unique",
- "nullsNotDistinct": false,
- "columns": [
- "token"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_sessions_known_devices": {
- "name": "core_sessions_known_devices",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "publicId": {
- "name": "publicId",
- "type": "varchar(32)",
- "primaryKey": false,
- "notNull": true
- },
- "ipAddress": {
- "name": "ipAddress",
- "type": "varchar(40)",
- "primaryKey": false,
- "notNull": true
- },
- "userAgent": {
- "name": "userAgent",
- "type": "text",
- "primaryKey": false,
- "notNull": true
- },
- "lastSeen": {
- "name": "lastSeen",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- }
- },
- "indexes": {
- "core_sessions_known_devices_ip_address_idx": {
- "name": "core_sessions_known_devices_ip_address_idx",
- "columns": [
- {
- "expression": "ipAddress",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_sessions_known_devices_publicId_unique": {
- "name": "core_sessions_known_devices_publicId_unique",
- "nullsNotDistinct": false,
- "columns": [
- "publicId"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_users": {
- "name": "core_users",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "nameCode": {
- "name": "nameCode",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "name": {
- "name": "name",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "email": {
- "name": "email",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "password": {
- "name": "password",
- "type": "varchar",
- "primaryKey": false,
- "notNull": false
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "newsletter": {
- "name": "newsletter",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "avatarColor": {
- "name": "avatarColor",
- "type": "varchar(6)",
- "primaryKey": false,
- "notNull": true
- },
- "emailVerified": {
- "name": "emailVerified",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "roleId": {
- "name": "roleId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "birthday": {
- "name": "birthday",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": false
- },
- "ipAddress": {
- "name": "ipAddress",
- "type": "varchar(40)",
- "primaryKey": false,
- "notNull": true
- },
- "language": {
- "name": "language",
- "type": "varchar(32)",
- "primaryKey": false,
- "notNull": true,
- "default": "'en'"
- }
- },
- "indexes": {
- "core_users_name_code_idx": {
- "name": "core_users_name_code_idx",
- "columns": [
- {
- "expression": "nameCode",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_users_name_idx": {
- "name": "core_users_name_idx",
- "columns": [
- {
- "expression": "name",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_users_email_idx": {
- "name": "core_users_email_idx",
- "columns": [
- {
- "expression": "email",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_users_roleId_core_roles_id_fk": {
- "name": "core_users_roleId_core_roles_id_fk",
- "tableFrom": "core_users",
- "tableTo": "core_roles",
- "columnsFrom": [
- "roleId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "no action",
- "onUpdate": "no action"
- },
- "core_users_language_core_languages_code_fk": {
- "name": "core_users_language_core_languages_code_fk",
- "tableFrom": "core_users",
- "tableTo": "core_languages",
- "columnsFrom": [
- "language"
- ],
- "columnsTo": [
- "code"
- ],
- "onDelete": "set default",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_users_nameCode_unique": {
- "name": "core_users_nameCode_unique",
- "nullsNotDistinct": false,
- "columns": [
- "nameCode"
- ]
- },
- "core_users_name_unique": {
- "name": "core_users_name_unique",
- "nullsNotDistinct": false,
- "columns": [
- "name"
- ]
- },
- "core_users_email_unique": {
- "name": "core_users_email_unique",
- "nullsNotDistinct": false,
- "columns": [
- "email"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_users_confirm_emails": {
- "name": "core_users_confirm_emails",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "token": {
- "name": "token",
- "type": "varchar(100)",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "expires": {
- "name": "expires",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {},
- "foreignKeys": {
- "core_users_confirm_emails_userId_core_users_id_fk": {
- "name": "core_users_confirm_emails_userId_core_users_id_fk",
- "tableFrom": "core_users_confirm_emails",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_users_confirm_emails_token_unique": {
- "name": "core_users_confirm_emails_token_unique",
- "nullsNotDistinct": false,
- "columns": [
- "token"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_users_forgot_password": {
- "name": "core_users_forgot_password",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "token": {
- "name": "token",
- "type": "varchar(100)",
- "primaryKey": false,
- "notNull": true
- },
- "ip_address": {
- "name": "ip_address",
- "type": "varchar(40)",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "expiresAt": {
- "name": "expiresAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {},
- "foreignKeys": {
- "core_users_forgot_password_userId_core_users_id_fk": {
- "name": "core_users_forgot_password_userId_core_users_id_fk",
- "tableFrom": "core_users_forgot_password",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_users_forgot_password_userId_unique": {
- "name": "core_users_forgot_password_userId_unique",
- "nullsNotDistinct": false,
- "columns": [
- "userId"
- ]
- },
- "core_users_forgot_password_token_unique": {
- "name": "core_users_forgot_password_token_unique",
- "nullsNotDistinct": false,
- "columns": [
- "token"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_users_sso": {
- "name": "core_users_sso",
- "schema": "",
- "columns": {
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "providerId": {
- "name": "providerId",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "providerAccountId": {
- "name": "providerAccountId",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {
- "core_users_sso_user_id_idx": {
- "name": "core_users_sso_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_users_sso_userId_core_users_id_fk": {
- "name": "core_users_sso_userId_core_users_id_fk",
- "tableFrom": "core_users_sso",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.blog_categories": {
- "name": "blog_categories",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "title": {
- "name": "title",
- "type": "varchar(100)",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "titleSeo": {
- "name": "titleSeo",
- "type": "varchar(100)",
- "primaryKey": false,
- "notNull": true,
- "default": "''"
- }
- },
- "indexes": {},
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "blog_categories_titleSeo_unique": {
- "name": "blog_categories_titleSeo_unique",
- "nullsNotDistinct": false,
- "columns": [
- "titleSeo"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.blog_posts": {
- "name": "blog_posts",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "title": {
- "name": "title",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "titleSeo": {
- "name": "titleSeo",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "content": {
- "name": "content",
- "type": "text",
- "primaryKey": false,
- "notNull": true
- },
- "categoryId": {
- "name": "categoryId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {},
- "foreignKeys": {
- "blog_posts_categoryId_blog_categories_id_fk": {
- "name": "blog_posts_categoryId_blog_categories_id_fk",
- "tableFrom": "blog_posts",
- "tableTo": "blog_categories",
- "columnsFrom": [
- "categoryId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "no action",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "blog_posts_titleSeo_unique": {
- "name": "blog_posts_titleSeo_unique",
- "nullsNotDistinct": false,
- "columns": [
- "titleSeo"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- }
- },
- "enums": {},
- "schemas": {},
- "sequences": {},
- "roles": {},
- "policies": {},
- "views": {},
- "_meta": {
- "columns": {},
- "schemas": {},
- "tables": {}
- }
-}
\ No newline at end of file
diff --git a/apps/web/migrations/meta/0002_snapshot.json b/apps/web/migrations/meta/0002_snapshot.json
deleted file mode 100644
index 678a7cb93..000000000
--- a/apps/web/migrations/meta/0002_snapshot.json
+++ /dev/null
@@ -1,1422 +0,0 @@
-{
- "id": "dc77dff2-5f35-42d7-84b1-6f6a96b81945",
- "prevId": "147890d3-87ad-4e29-a83e-43b220c8af80",
- "version": "7",
- "dialect": "postgresql",
- "tables": {
- "public.core_admin_permissions": {
- "name": "core_admin_permissions",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "roleId": {
- "name": "roleId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "protected": {
- "name": "protected",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- }
- },
- "indexes": {
- "core_admin_permissions_role_id_idx": {
- "name": "core_admin_permissions_role_id_idx",
- "columns": [
- {
- "expression": "roleId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_admin_permissions_user_id_idx": {
- "name": "core_admin_permissions_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_admin_permissions_roleId_core_roles_id_fk": {
- "name": "core_admin_permissions_roleId_core_roles_id_fk",
- "tableFrom": "core_admin_permissions",
- "tableTo": "core_roles",
- "columnsFrom": [
- "roleId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "core_admin_permissions_userId_core_users_id_fk": {
- "name": "core_admin_permissions_userId_core_users_id_fk",
- "tableFrom": "core_admin_permissions",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_admin_sessions": {
- "name": "core_admin_sessions",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "token": {
- "name": "token",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "lastSeen": {
- "name": "lastSeen",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "expiresAt": {
- "name": "expiresAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "deviceId": {
- "name": "deviceId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {
- "core_admin_sessions_token_idx": {
- "name": "core_admin_sessions_token_idx",
- "columns": [
- {
- "expression": "token",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_admin_sessions_user_id_idx": {
- "name": "core_admin_sessions_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_admin_sessions_userId_core_users_id_fk": {
- "name": "core_admin_sessions_userId_core_users_id_fk",
- "tableFrom": "core_admin_sessions",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "core_admin_sessions_deviceId_core_sessions_known_devices_id_fk": {
- "name": "core_admin_sessions_deviceId_core_sessions_known_devices_id_fk",
- "tableFrom": "core_admin_sessions",
- "tableTo": "core_sessions_known_devices",
- "columnsFrom": [
- "deviceId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_admin_sessions_token_unique": {
- "name": "core_admin_sessions_token_unique",
- "nullsNotDistinct": false,
- "columns": [
- "token"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_languages": {
- "name": "core_languages",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "code": {
- "name": "code",
- "type": "varchar(32)",
- "primaryKey": false,
- "notNull": true
- },
- "name": {
- "name": "name",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "timezone": {
- "name": "timezone",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true,
- "default": "'UTC'"
- },
- "protected": {
- "name": "protected",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "default": {
- "name": "default",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "enabled": {
- "name": "enabled",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "time24": {
- "name": "time24",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- }
- },
- "indexes": {
- "core_languages_code_idx": {
- "name": "core_languages_code_idx",
- "columns": [
- {
- "expression": "code",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_languages_name_idx": {
- "name": "core_languages_name_idx",
- "columns": [
- {
- "expression": "name",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_languages_code_unique": {
- "name": "core_languages_code_unique",
- "nullsNotDistinct": false,
- "columns": [
- "code"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_languages_words": {
- "name": "core_languages_words",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "languageCode": {
- "name": "languageCode",
- "type": "varchar",
- "primaryKey": false,
- "notNull": true
- },
- "pluginCode": {
- "name": "pluginCode",
- "type": "varchar(50)",
- "primaryKey": false,
- "notNull": true
- },
- "itemId": {
- "name": "itemId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "value": {
- "name": "value",
- "type": "text",
- "primaryKey": false,
- "notNull": true
- },
- "tableName": {
- "name": "tableName",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "variable": {
- "name": "variable",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {
- "core_languages_words_lang_code_idx": {
- "name": "core_languages_words_lang_code_idx",
- "columns": [
- {
- "expression": "languageCode",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_languages_words_languageCode_core_languages_code_fk": {
- "name": "core_languages_words_languageCode_core_languages_code_fk",
- "tableFrom": "core_languages_words",
- "tableTo": "core_languages",
- "columnsFrom": [
- "languageCode"
- ],
- "columnsTo": [
- "code"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_logs": {
- "name": "core_logs",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "pluginCode": {
- "name": "pluginCode",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "type": {
- "name": "type",
- "type": "typeLogs",
- "typeSchema": "public",
- "primaryKey": false,
- "notNull": true,
- "default": "'info'"
- },
- "content": {
- "name": "content",
- "type": "text",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "ipAddress": {
- "name": "ipAddress",
- "type": "varchar(45)",
- "primaryKey": false,
- "notNull": true,
- "default": "''"
- }
- },
- "indexes": {},
- "foreignKeys": {
- "core_logs_userId_core_users_id_fk": {
- "name": "core_logs_userId_core_users_id_fk",
- "tableFrom": "core_logs",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "set null",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_moderators_permissions": {
- "name": "core_moderators_permissions",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "roleId": {
- "name": "roleId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": false
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "protected": {
- "name": "protected",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- }
- },
- "indexes": {
- "core_moderators_permissions_role_id_idx": {
- "name": "core_moderators_permissions_role_id_idx",
- "columns": [
- {
- "expression": "roleId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_moderators_permissions_user_id_idx": {
- "name": "core_moderators_permissions_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_moderators_permissions_roleId_core_roles_id_fk": {
- "name": "core_moderators_permissions_roleId_core_roles_id_fk",
- "tableFrom": "core_moderators_permissions",
- "tableTo": "core_roles",
- "columnsFrom": [
- "roleId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "core_moderators_permissions_userId_core_users_id_fk": {
- "name": "core_moderators_permissions_userId_core_users_id_fk",
- "tableFrom": "core_moderators_permissions",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_roles": {
- "name": "core_roles",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "protected": {
- "name": "protected",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "default": {
- "name": "default",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "root": {
- "name": "root",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "guest": {
- "name": "guest",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "color": {
- "name": "color",
- "type": "varchar(19)",
- "primaryKey": false,
- "notNull": false
- }
- },
- "indexes": {},
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_sessions": {
- "name": "core_sessions",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "token": {
- "name": "token",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "expiresAt": {
- "name": "expiresAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "deviceId": {
- "name": "deviceId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {
- "core_sessions_user_id_idx": {
- "name": "core_sessions_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_sessions_userId_core_users_id_fk": {
- "name": "core_sessions_userId_core_users_id_fk",
- "tableFrom": "core_sessions",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- },
- "core_sessions_deviceId_core_sessions_known_devices_id_fk": {
- "name": "core_sessions_deviceId_core_sessions_known_devices_id_fk",
- "tableFrom": "core_sessions",
- "tableTo": "core_sessions_known_devices",
- "columnsFrom": [
- "deviceId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_sessions_token_unique": {
- "name": "core_sessions_token_unique",
- "nullsNotDistinct": false,
- "columns": [
- "token"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_sessions_known_devices": {
- "name": "core_sessions_known_devices",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "publicId": {
- "name": "publicId",
- "type": "varchar(32)",
- "primaryKey": false,
- "notNull": true
- },
- "ipAddress": {
- "name": "ipAddress",
- "type": "varchar(40)",
- "primaryKey": false,
- "notNull": true
- },
- "userAgent": {
- "name": "userAgent",
- "type": "text",
- "primaryKey": false,
- "notNull": true
- },
- "lastSeen": {
- "name": "lastSeen",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- }
- },
- "indexes": {
- "core_sessions_known_devices_ip_address_idx": {
- "name": "core_sessions_known_devices_ip_address_idx",
- "columns": [
- {
- "expression": "ipAddress",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_sessions_known_devices_publicId_unique": {
- "name": "core_sessions_known_devices_publicId_unique",
- "nullsNotDistinct": false,
- "columns": [
- "publicId"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_users": {
- "name": "core_users",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "nameCode": {
- "name": "nameCode",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "name": {
- "name": "name",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "email": {
- "name": "email",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "password": {
- "name": "password",
- "type": "varchar",
- "primaryKey": false,
- "notNull": false
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "newsletter": {
- "name": "newsletter",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "avatarColor": {
- "name": "avatarColor",
- "type": "varchar(6)",
- "primaryKey": false,
- "notNull": true
- },
- "emailVerified": {
- "name": "emailVerified",
- "type": "boolean",
- "primaryKey": false,
- "notNull": true,
- "default": false
- },
- "roleId": {
- "name": "roleId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "birthday": {
- "name": "birthday",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": false
- },
- "ipAddress": {
- "name": "ipAddress",
- "type": "varchar(40)",
- "primaryKey": false,
- "notNull": true
- },
- "language": {
- "name": "language",
- "type": "varchar(32)",
- "primaryKey": false,
- "notNull": true,
- "default": "'en'"
- }
- },
- "indexes": {
- "core_users_name_code_idx": {
- "name": "core_users_name_code_idx",
- "columns": [
- {
- "expression": "nameCode",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_users_name_idx": {
- "name": "core_users_name_idx",
- "columns": [
- {
- "expression": "name",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- },
- "core_users_email_idx": {
- "name": "core_users_email_idx",
- "columns": [
- {
- "expression": "email",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_users_roleId_core_roles_id_fk": {
- "name": "core_users_roleId_core_roles_id_fk",
- "tableFrom": "core_users",
- "tableTo": "core_roles",
- "columnsFrom": [
- "roleId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "no action",
- "onUpdate": "no action"
- },
- "core_users_language_core_languages_code_fk": {
- "name": "core_users_language_core_languages_code_fk",
- "tableFrom": "core_users",
- "tableTo": "core_languages",
- "columnsFrom": [
- "language"
- ],
- "columnsTo": [
- "code"
- ],
- "onDelete": "set default",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_users_nameCode_unique": {
- "name": "core_users_nameCode_unique",
- "nullsNotDistinct": false,
- "columns": [
- "nameCode"
- ]
- },
- "core_users_name_unique": {
- "name": "core_users_name_unique",
- "nullsNotDistinct": false,
- "columns": [
- "name"
- ]
- },
- "core_users_email_unique": {
- "name": "core_users_email_unique",
- "nullsNotDistinct": false,
- "columns": [
- "email"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_users_confirm_emails": {
- "name": "core_users_confirm_emails",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "token": {
- "name": "token",
- "type": "varchar(100)",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "expires": {
- "name": "expires",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {},
- "foreignKeys": {
- "core_users_confirm_emails_userId_core_users_id_fk": {
- "name": "core_users_confirm_emails_userId_core_users_id_fk",
- "tableFrom": "core_users_confirm_emails",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_users_confirm_emails_token_unique": {
- "name": "core_users_confirm_emails_token_unique",
- "nullsNotDistinct": false,
- "columns": [
- "token"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_users_forgot_password": {
- "name": "core_users_forgot_password",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "token": {
- "name": "token",
- "type": "varchar(100)",
- "primaryKey": false,
- "notNull": true
- },
- "ip_address": {
- "name": "ip_address",
- "type": "varchar(40)",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "expiresAt": {
- "name": "expiresAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {},
- "foreignKeys": {
- "core_users_forgot_password_userId_core_users_id_fk": {
- "name": "core_users_forgot_password_userId_core_users_id_fk",
- "tableFrom": "core_users_forgot_password",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "core_users_forgot_password_userId_unique": {
- "name": "core_users_forgot_password_userId_unique",
- "nullsNotDistinct": false,
- "columns": [
- "userId"
- ]
- },
- "core_users_forgot_password_token_unique": {
- "name": "core_users_forgot_password_token_unique",
- "nullsNotDistinct": false,
- "columns": [
- "token"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.core_users_sso": {
- "name": "core_users_sso",
- "schema": "",
- "columns": {
- "userId": {
- "name": "userId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "providerId": {
- "name": "providerId",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "providerAccountId": {
- "name": "providerAccountId",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {
- "core_users_sso_user_id_idx": {
- "name": "core_users_sso_user_id_idx",
- "columns": [
- {
- "expression": "userId",
- "isExpression": false,
- "asc": true,
- "nulls": "last"
- }
- ],
- "isUnique": false,
- "concurrently": false,
- "method": "btree",
- "with": {}
- }
- },
- "foreignKeys": {
- "core_users_sso_userId_core_users_id_fk": {
- "name": "core_users_sso_userId_core_users_id_fk",
- "tableFrom": "core_users_sso",
- "tableTo": "core_users",
- "columnsFrom": [
- "userId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "cascade",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {},
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.blog_categories": {
- "name": "blog_categories",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "title": {
- "name": "title",
- "type": "varchar(100)",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- },
- "titleSeo": {
- "name": "titleSeo",
- "type": "varchar(100)",
- "primaryKey": false,
- "notNull": true,
- "default": "''"
- }
- },
- "indexes": {},
- "foreignKeys": {},
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "blog_categories_titleSeo_unique": {
- "name": "blog_categories_titleSeo_unique",
- "nullsNotDistinct": false,
- "columns": [
- "titleSeo"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- },
- "public.blog_posts": {
- "name": "blog_posts",
- "schema": "",
- "columns": {
- "id": {
- "name": "id",
- "type": "serial",
- "primaryKey": true,
- "notNull": true
- },
- "title": {
- "name": "title",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "titleSeo": {
- "name": "titleSeo",
- "type": "varchar(255)",
- "primaryKey": false,
- "notNull": true
- },
- "content": {
- "name": "content",
- "type": "text",
- "primaryKey": false,
- "notNull": true
- },
- "categoryId": {
- "name": "categoryId",
- "type": "integer",
- "primaryKey": false,
- "notNull": true
- },
- "createdAt": {
- "name": "createdAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true,
- "default": "now()"
- },
- "updatedAt": {
- "name": "updatedAt",
- "type": "timestamp",
- "primaryKey": false,
- "notNull": true
- }
- },
- "indexes": {},
- "foreignKeys": {
- "blog_posts_categoryId_blog_categories_id_fk": {
- "name": "blog_posts_categoryId_blog_categories_id_fk",
- "tableFrom": "blog_posts",
- "tableTo": "blog_categories",
- "columnsFrom": [
- "categoryId"
- ],
- "columnsTo": [
- "id"
- ],
- "onDelete": "no action",
- "onUpdate": "no action"
- }
- },
- "compositePrimaryKeys": {},
- "uniqueConstraints": {
- "blog_posts_titleSeo_unique": {
- "name": "blog_posts_titleSeo_unique",
- "nullsNotDistinct": false,
- "columns": [
- "titleSeo"
- ]
- }
- },
- "policies": {},
- "checkConstraints": {},
- "isRLSEnabled": true
- }
- },
- "enums": {
- "public.typeLogs": {
- "name": "typeLogs",
- "schema": "public",
- "values": [
- "info",
- "warn",
- "error",
- "debug"
- ]
- }
- },
- "schemas": {},
- "sequences": {},
- "roles": {},
- "policies": {},
- "views": {},
- "_meta": {
- "columns": {},
- "schemas": {},
- "tables": {}
- }
-}
\ No newline at end of file
diff --git a/apps/web/migrations/meta/_journal.json b/apps/web/migrations/meta/_journal.json
index 1d68d9686..26c27fd9e 100644
--- a/apps/web/migrations/meta/_journal.json
+++ b/apps/web/migrations/meta/_journal.json
@@ -5,22 +5,8 @@
{
"idx": 0,
"version": "7",
- "when": 1749828219011,
- "tag": "0000_overjoyed_sandman",
- "breakpoints": true
- },
- {
- "idx": 1,
- "version": "7",
- "when": 1750322132661,
- "tag": "0001_mute_flatman",
- "breakpoints": true
- },
- {
- "idx": 2,
- "version": "7",
- "when": 1750493644570,
- "tag": "0002_superb_natasha_romanoff",
+ "when": 1750691750823,
+ "tag": "0000_stormy_ronan",
"breakpoints": true
}
]
diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx
index 38ce51e93..dcc322a09 100644
--- a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx
+++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx
@@ -7,7 +7,12 @@ import { getTranslations } from 'next-intl/server';
import React from 'react';
import { ActionsCategoriesAdmin } from '@vitnode/blog/views/admin/categories/actions/actions';
-import { CategoriesAdminView } from '@vitnode/blog/views/admin/categories/categories-admin-view';
+
+const CategoriesAdminView = React.lazy(async () =>
+ import('@vitnode/blog/views/admin/categories/categories-admin-view').then(mod => ({
+ default: mod.CategoriesAdminView,
+ })),
+);
export const generateMetadata = async (): Promise => {
const t = await getTranslations('@vitnode/blog.admin.nav');
diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/posts/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/posts/page.tsx
index f2163bd36..7f45c40e9 100644
--- a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/posts/page.tsx
+++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/posts/page.tsx
@@ -7,7 +7,12 @@ import { getTranslations } from 'next-intl/server';
import React from 'react';
import { ActionsPostsAdmin } from '@vitnode/blog/views/admin/posts/actions/actions';
-import { PostsAdminView } from '@vitnode/blog/views/admin/posts/posts-admin-view';
+
+const PostsAdminView = React.lazy(async () =>
+ import('@vitnode/blog/views/admin/posts/posts-admin-view').then(mod => ({
+ default: mod.PostsAdminView,
+ })),
+);
export const generateMetadata = async (): Promise => {
const t = await getTranslations('@vitnode/blog.admin.nav');
diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/debug/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/debug/page.tsx
index 6c3124468..cfda4a29a 100644
--- a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/debug/page.tsx
+++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/debug/page.tsx
@@ -1,9 +1,16 @@
import { getTranslations } from 'next-intl/server';
+import React from 'react';
import { I18nProvider } from '@vitnode/core/components/i18n-provider';
+import { DataTableSkeleton } from '@vitnode/core/components/table/data-table';
import { HeaderContent } from '@vitnode/core/components/ui/header-content';
import { ClearCacheAction } from '@vitnode/core/views/admin/views/core/debug/actions/clear-cache/clear-cache';
-import { DebugAdminView } from '@vitnode/core/views/admin/views/core/debug/debug-admin-view';
+
+const DebugAdminView = React.lazy(async () =>
+ import('@vitnode/core/views/admin/views/core/debug/debug-admin-view').then(module => ({
+ default: module.DebugAdminView,
+ })),
+);
export const generateMetadata = async () => {
const t = await getTranslations('admin.debug');
@@ -14,7 +21,9 @@ export const generateMetadata = async () => {
};
};
-export default async function Page() {
+export default async function Page(
+ props: React.ComponentProps,
+) {
const t = await getTranslations('admin.debug');
return (
@@ -24,7 +33,10 @@ export default async function Page() {
-
+
+ }>
+
+
);
diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/users/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/users/page.tsx
index 92394f9be..b4a0323b0 100644
--- a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/users/page.tsx
+++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-core)/core/users/page.tsx
@@ -5,7 +5,12 @@ import React from 'react';
import { DataTableSkeleton } from '@vitnode/core/components/table/data-table';
import { HeaderContent } from '@vitnode/core/components/ui/header-content';
-import { UsersAdminView } from '@vitnode/core/views/admin/views/core/users/users-admin-view';
+
+const UsersAdminView = React.lazy(async () =>
+ import('@vitnode/core/views/admin/views/core/users/users-admin-view').then(module => ({
+ default: module.UsersAdminView,
+ })),
+);
export const generateMetadata = async (): Promise => {
const t = await getTranslations('admin.global.nav.users');
diff --git a/apps/web/src/app/global.css b/apps/web/src/app/global.css
index 27f4d2ad0..ef1bf8194 100644
--- a/apps/web/src/app/global.css
+++ b/apps/web/src/app/global.css
@@ -22,8 +22,8 @@
--muted-foreground: oklch(0.45 0 0);
--accent: oklch(0.95 0 0);
--accent-foreground: oklch(0.205 0 0);
- --destructive: oklch(0.577 0.245 27.325);
- --destructive-foreground: oklch(0.577 0.245 27.325);
+ --destructive: oklch(0.6 0.2 24.45);
+ --warn: oklch(0.57 0.13 82.37);
--border: oklch(0.9 0 0);
--input: oklch(0.9 0 0);
--ring: oklch(0.7 0.16 262.61);
@@ -56,8 +56,8 @@
--muted: oklch(0.22 0 0);
--muted-foreground: oklch(0.7 0 0);
--accent: oklch(0.28 0 0);
- --destructive: oklch(0.704 0.191 22.216);
- --destructive-foreground: oklch(0.704 0.191 22.216);
+ --destructive: oklch(0.62 0.2 25.35);
+ --warn: oklch(0.76 0.18 81.84);
--border: oklch(0.28 0 0);
--input: oklch(0.28 0 0);
--ring: oklch(0.51 0.16 262.61);
@@ -96,7 +96,7 @@
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
- --color-destructive-foreground: var(--destructive-foreground);
+ --color-warn: var(--warn);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
diff --git a/apps/web/src/locales/@vitnode/core/en.json b/apps/web/src/locales/@vitnode/core/en.json
index 0890d7c28..a3b9c9560 100644
--- a/apps/web/src/locales/@vitnode/core/en.json
+++ b/apps/web/src/locales/@vitnode/core/en.json
@@ -170,6 +170,19 @@
"success": "Cache cleared successfully.",
"confirm": "Yes, clear cache"
}
+ },
+ "logs": {
+ "title": "System Logs",
+ "id": "ID",
+ "created_at": "Created At",
+ "plugin": "Plugin",
+ "content": "Content",
+ "type": "Type",
+ "types": {
+ "warn": "Warning",
+ "error": "Error",
+ "debug": "Debug"
+ }
}
}
}
diff --git a/packages/vitnode/scripts/shared/file-utils.ts b/packages/vitnode/scripts/shared/file-utils.ts
index 764c24ace..957583aa5 100644
--- a/packages/vitnode/scripts/shared/file-utils.ts
+++ b/packages/vitnode/scripts/shared/file-utils.ts
@@ -22,6 +22,7 @@ const relativeImportRegex =
/import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"]([./]+[^'"]*)['"]/g;
const atImportRegex =
/import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"](@\/[^'"]*)['"]/g;
+const dynamicAtImportRegex = /import\s*\(\s*['"](@\/[^'"]*)['"]\s*\)/g;
const jsExtensionRegex = /\.(js|jsx|ts|tsx)$/;
const pageFileRegex = /^page\.(tsx|ts|jsx|js)$/i;
@@ -105,6 +106,20 @@ export const transformFileImports = (
},
);
+ // Handle dynamic imports (React.lazy) with @/ paths
+ transformedContent = transformedContent.replace(
+ dynamicAtImportRegex,
+ (match, importPath: string) => {
+ // Remove '@/' prefix and any file extensions
+ const cleanPath = importPath
+ .replace(/^@\//, '')
+ .replace(jsExtensionRegex, '');
+ // Return the package import format
+
+ return match.replace(importPath, `${pluginName}/${cleanPath}`);
+ },
+ );
+
return transformedContent;
};
diff --git a/packages/vitnode/src/api/config.ts b/packages/vitnode/src/api/config.ts
index 13511351f..be3e25d23 100644
--- a/packages/vitnode/src/api/config.ts
+++ b/packages/vitnode/src/api/config.ts
@@ -75,13 +75,12 @@ export function VitNodeAPI({
return next();
});
- app.onError(error => {
+ app.onError((error, c) => {
if (error instanceof HTTPException) {
return error.getResponse();
}
- // eslint-disable-next-line no-console
- console.error(error);
+ c.get('log').error(`Unhandled error: ${error.message}`);
return new Response(
process.env.NODE_ENV === 'development'
diff --git a/packages/vitnode/src/api/lib/get-user-ip.ts b/packages/vitnode/src/api/lib/get-user-ip.ts
deleted file mode 100644
index ad9caafb9..000000000
--- a/packages/vitnode/src/api/lib/get-user-ip.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import type { Context } from 'hono';
-
-export const getUserIp = (c: Context): string => {
- const ip: string = c.req.header('x-forwarded-for')?.toString() ?? '0.0.0.0';
-
- if (ip === '0.0.0.0') {
- // eslint-disable-next-line no-console
- console.error(
- '\x1b[31m[VitNode]\x1b[31m No IP found in request. Please check if you passed `x-forwarded-for` header.\x1b[0m',
- );
- }
-
- return ip;
-};
diff --git a/packages/vitnode/src/api/lib/logger-middleware.ts b/packages/vitnode/src/api/lib/logger-middleware.ts
new file mode 100644
index 000000000..929c0e2a9
--- /dev/null
+++ b/packages/vitnode/src/api/lib/logger-middleware.ts
@@ -0,0 +1,52 @@
+/* eslint-disable no-console */
+import type { Context } from 'hono';
+
+import { core_logs, type CoreLogsType } from '@/database/logs';
+
+export interface LoggerMiddlewareType {
+ debug: (content: string) => void;
+ error: (content: string) => void;
+ warn: (content: string) => void;
+}
+
+export const loggerMiddleware = (c: Context): LoggerMiddlewareType => {
+ const logToDbAndConsole = async (content: string, type: CoreLogsType) => {
+ const pluginId = c.get('plugin')?.id ?? 'core';
+ const ipAddress = c.get('ipAddress');
+
+ await c.get('db').insert(core_logs).values({
+ pluginId,
+ type,
+ content,
+ ipAddress,
+ });
+
+ const loggers: Record void> = {
+ debug: msg =>
+ console.debug(
+ `\x1b[34m[VitNode]\x1b[0m \x1b[38;5;208mDebug (${pluginId})\x1b[0m: ${msg}`,
+ ),
+ error: msg =>
+ console.error(
+ `\x1b[34m[VitNode]\x1b[0m \x1b[31mError (${pluginId})\x1b[0m: ${msg}`,
+ ),
+ warn: msg =>
+ console.warn(
+ `\x1b[34m[VitNode]\x1b[0m \x1b[33mWarning (${pluginId})\x1b[0m: ${msg}`,
+ ),
+ };
+ (loggers[type] ?? loggers.debug)(content);
+ };
+
+ return {
+ debug: (content: string) => {
+ void logToDbAndConsole(content, 'debug');
+ },
+ error: (content: string) => {
+ void logToDbAndConsole(content, 'error');
+ },
+ warn: (content: string) => {
+ void logToDbAndConsole(content, 'warn');
+ },
+ };
+};
diff --git a/packages/vitnode/src/api/middlewares/global.middleware.ts b/packages/vitnode/src/api/middlewares/global.middleware.ts
index 1edd9c5d8..889163af4 100644
--- a/packages/vitnode/src/api/middlewares/global.middleware.ts
+++ b/packages/vitnode/src/api/middlewares/global.middleware.ts
@@ -10,6 +10,11 @@ import { SessionAdminModel } from '@/api/models/session-admin';
import type { SSOApiPlugin } from '../models/sso';
+import {
+ loggerMiddleware,
+ type LoggerMiddlewareType,
+} from '../lib/logger-middleware';
+
export interface EnvVitNode extends Env {
Variables: EnvVariablesVitNode;
}
@@ -47,6 +52,8 @@ interface EnvVariablesVitNode {
};
};
db: Pick['dbProvider'];
+ ipAddress: string;
+ log: LoggerMiddlewareType;
plugin: {
id: string;
};
@@ -77,6 +84,50 @@ export const globalMiddleware = ({
}: Pick &
Pick) => {
return async (c: Context, next: Next) => {
+ // Collect possible IP header keys in order of trust/preference
+ const ipHeaderKeys = [
+ 'x-forwarded-for',
+ 'x-real-ip',
+ 'cf-connecting-ip',
+ 'x-client-ip',
+ 'x-forwarded',
+ 'x-cluster-client-ip',
+ 'forwarded-for',
+ 'forwarded',
+ 'via',
+ 'remote-addr',
+ 'client-ip',
+ 'ip',
+ 'x-ip',
+ 'true-client-ip',
+ 'fastly-client-ip',
+ 'x-fastly-client-ip',
+ ];
+
+ let ipAddress: string | undefined;
+
+ // Try to get IP from Hono's request header method first
+ for (const key of ipHeaderKeys) {
+ const value = c.req.header(key);
+ if (value) {
+ ipAddress = value;
+ break;
+ }
+ }
+
+ // If not found, try raw headers (for edge runtimes, etc.)
+ if (!ipAddress) {
+ for (const key of ipHeaderKeys) {
+ const value = c.req.raw.headers.get(key);
+ if (value) {
+ ipAddress = value;
+ break;
+ }
+ }
+ }
+
+ // Fallback to localhost if nothing found
+ c.set('ipAddress', ipAddress ?? '127.0.0.1');
c.set('db', dbProvider);
c.set('core', {
@@ -100,6 +151,7 @@ export const globalMiddleware = ({
const user = await new SessionModel(c).getUser();
c.set('user', user);
c.set('admin', null);
+ c.set('log', loggerMiddleware(c));
await next();
};
diff --git a/packages/vitnode/src/api/middlewares/rate-limiter.middleware.ts b/packages/vitnode/src/api/middlewares/rate-limiter.middleware.ts
index 72a1dd7b5..6d45cea50 100644
--- a/packages/vitnode/src/api/middlewares/rate-limiter.middleware.ts
+++ b/packages/vitnode/src/api/middlewares/rate-limiter.middleware.ts
@@ -6,6 +6,8 @@ import {
RateLimiterMemory,
} from 'rate-limiter-flexible';
+import { CONFIG } from '../../lib/config';
+
const createRateLimiter = ({
keyPrefix,
...options
@@ -16,7 +18,7 @@ const createRateLimiter = ({
return new RateLimiterMemory({
keyPrefix,
- points: options?.points ?? 40, // 40 requests
+ points: CONFIG.node_development ? 120 : (options?.points ?? 80), // 120 req in dev, 80 in prod
duration: options?.duration ?? 60, // per 60 seconds
...options,
});
@@ -31,10 +33,7 @@ export const rateLimiterMiddleware = (
});
return async (c: Context, next: Next) => {
- const key =
- c.req.header('x-forwarded-for') ??
- c.req.raw.headers.get('x-real-ip') ??
- '127.0.0.1';
+ const key = c.get('ipAddress');
try {
await rateLimiter.consume(key);
diff --git a/packages/vitnode/src/api/models/device.ts b/packages/vitnode/src/api/models/device.ts
index 99190a0b5..629239a01 100644
--- a/packages/vitnode/src/api/models/device.ts
+++ b/packages/vitnode/src/api/models/device.ts
@@ -7,8 +7,6 @@ import { getCookie, setCookie } from 'hono/cookie';
import { core_sessions_known_devices } from '@/database/sessions';
import { CONFIG } from '@/lib/config';
-import { getUserIp } from '../lib/get-user-ip';
-
export class DeviceModel {
constructor(c: Context) {
this.c = c;
@@ -23,7 +21,7 @@ export class DeviceModel {
.insert(core_sessions_known_devices)
.values({
publicId,
- ipAddress: getUserIp(this.c),
+ ipAddress: this.c.get('ipAddress'),
userAgent: this.getUserAgent(),
})
.returning({ id: core_sessions_known_devices.id });
@@ -78,7 +76,7 @@ export class DeviceModel {
.get('db')
.update(core_sessions_known_devices)
.set({
- ipAddress: getUserIp(this.c),
+ ipAddress: this.c.get('ipAddress'),
userAgent: this.getUserAgent(),
})
.where(eq(core_sessions_known_devices.publicId, deviceIdFromCookie));
diff --git a/packages/vitnode/src/api/models/email.ts b/packages/vitnode/src/api/models/email.ts
index 218a6200f..a2a0ee266 100644
--- a/packages/vitnode/src/api/models/email.ts
+++ b/packages/vitnode/src/api/models/email.ts
@@ -28,10 +28,18 @@ export class EmailModel {
});
}
- // TODO: Add logging when email is failed to send
- void provider.sendEmail({
- ...args,
- metadata: core.metadata,
- });
+ void provider
+ .sendEmail({
+ ...args,
+ metadata: core.metadata,
+ })
+ .catch((err: unknown) => {
+ const error =
+ err instanceof Error
+ ? err
+ : new Error('Unknown error from email provider');
+
+ this.c.get('log').error(`Failed to send email: ${error.message}`);
+ });
}
}
diff --git a/packages/vitnode/src/api/models/user/sign-up.ts b/packages/vitnode/src/api/models/user/sign-up.ts
index d5f3a6615..cd98e6977 100644
--- a/packages/vitnode/src/api/models/user/sign-up.ts
+++ b/packages/vitnode/src/api/models/user/sign-up.ts
@@ -3,7 +3,6 @@ import type { Context } from 'hono';
import { and, count, eq, or } from 'drizzle-orm';
import { HTTPException } from 'hono/http-exception';
-import { getUserIp } from '@/api/lib/get-user-ip';
import { generateAvatarColor } from '@/api/modules/users/avatar-color';
import { core_roles } from '@/database/roles';
import { core_users } from '@/database/users';
@@ -122,7 +121,7 @@ export const signUp = async (
avatarColor: generateAvatarColor(name),
roleId,
emailVerified,
- ipAddress: getUserIp(c),
+ ipAddress: c.get('ipAddress'),
// TODO: Handle language
// language: await this.getLanguage(req),
})
diff --git a/packages/vitnode/src/api/modules/admin/admin.module.ts b/packages/vitnode/src/api/modules/admin/admin.module.ts
index e3d3ed8eb..81cc2e8df 100644
--- a/packages/vitnode/src/api/modules/admin/admin.module.ts
+++ b/packages/vitnode/src/api/modules/admin/admin.module.ts
@@ -1,6 +1,7 @@
import { buildModule } from '@/api/lib/module';
import { CONFIG_PLUGIN } from '@/config';
+import { debugAdminModule } from './debug/debug.admin.module';
import { sessionAdminRoute } from './routes/session.route';
import { usersAdminModule } from './users/users.admin.module';
@@ -8,5 +9,5 @@ export const adminModule = buildModule({
...CONFIG_PLUGIN,
name: 'admin',
routes: [sessionAdminRoute],
- modules: [usersAdminModule],
+ modules: [usersAdminModule, debugAdminModule],
});
diff --git a/packages/vitnode/src/api/modules/admin/debug/debug.admin.module.ts b/packages/vitnode/src/api/modules/admin/debug/debug.admin.module.ts
new file mode 100644
index 000000000..316227e1c
--- /dev/null
+++ b/packages/vitnode/src/api/modules/admin/debug/debug.admin.module.ts
@@ -0,0 +1,9 @@
+import { CONFIG_PLUGIN } from '../../../../config';
+import { buildModule } from '../../../lib/module';
+import { logsDebugAdminRoute } from './routes/logs.route';
+
+export const debugAdminModule = buildModule({
+ ...CONFIG_PLUGIN,
+ name: 'debug',
+ routes: [logsDebugAdminRoute],
+});
diff --git a/packages/vitnode/src/api/modules/admin/debug/routes/logs.route.ts b/packages/vitnode/src/api/modules/admin/debug/routes/logs.route.ts
new file mode 100644
index 000000000..a9d10cdab
--- /dev/null
+++ b/packages/vitnode/src/api/modules/admin/debug/routes/logs.route.ts
@@ -0,0 +1,80 @@
+import { z } from 'zod';
+
+import { CONFIG_PLUGIN } from '@/config';
+import { core_logs, coreLogsType } from '@/database/logs';
+
+import { buildRoute } from '../../../../lib/route';
+import {
+ withPagination,
+ zodPaginationPageInfo,
+ zodPaginationQuery,
+} from '../../../../lib/with-pagination';
+
+export const logsDebugAdminRoute = buildRoute({
+ ...CONFIG_PLUGIN,
+ route: {
+ method: 'get',
+ description: 'Get Admin Debug Logs',
+ path: '/logs',
+ request: {
+ query: zodPaginationQuery.extend({
+ order: z.enum(['asc', 'desc']).optional(),
+ orderBy: z.enum(['type', 'createdAt', 'pluginId']).optional(),
+ }),
+ },
+ responses: {
+ 200: {
+ content: {
+ 'application/json': {
+ schema: z.object({
+ edges: z.array(
+ z.object({
+ id: z.number(),
+ pluginId: z.string(),
+ type: z.enum(coreLogsType.enumValues),
+ content: z.string(),
+ createdAt: z.date(),
+ ipAddress: z.string(),
+ }),
+ ),
+ pageInfo: zodPaginationPageInfo,
+ }),
+ },
+ },
+ description: 'List of users',
+ },
+ },
+ },
+ handler: async c => {
+ const query = c.req.valid('query');
+ const data = await withPagination({
+ params: {
+ query,
+ },
+ primaryCursor: core_logs.id,
+ query: async ({ limit, where, orderBy }) =>
+ await c
+ .get('db')
+ .select({
+ id: core_logs.id,
+ pluginId: core_logs.pluginId,
+ type: core_logs.type,
+ content: core_logs.content,
+ createdAt: core_logs.createdAt,
+ ipAddress: core_logs.ipAddress,
+ })
+ .from(core_logs)
+ .where(where)
+ .orderBy(orderBy)
+ .limit(limit),
+ table: core_logs,
+ orderBy: {
+ column: query.orderBy ? core_logs[query.orderBy] : core_logs.createdAt,
+ order: query.order ?? 'desc',
+ },
+ c,
+ });
+
+ return c.json(data);
+ },
+});
diff --git a/packages/vitnode/src/api/modules/admin/routes/session.route.ts b/packages/vitnode/src/api/modules/admin/routes/session.route.ts
index ca719bb51..4de23c1eb 100644
--- a/packages/vitnode/src/api/modules/admin/routes/session.route.ts
+++ b/packages/vitnode/src/api/modules/admin/routes/session.route.ts
@@ -9,10 +9,6 @@ export const sessionAdminRoute = buildRoute({
route: {
method: 'get',
description: 'Verify admin session',
- pluginConfig: {
- id: 'core',
- name: 'Core',
- },
path: '/session',
responses: {
200: {
diff --git a/packages/vitnode/src/api/modules/users/routes/test.route.ts b/packages/vitnode/src/api/modules/users/routes/test.route.ts
index 53dfe0cc9..817ac56aa 100644
--- a/packages/vitnode/src/api/modules/users/routes/test.route.ts
+++ b/packages/vitnode/src/api/modules/users/routes/test.route.ts
@@ -3,7 +3,7 @@ import { z } from 'zod';
import { buildRoute } from '@/api/lib/route';
import { CONFIG_PLUGIN } from '@/config';
-import { EmailModel } from '../../../models/email';
+// import { EmailModel } from '../../../models/email';
export const testRoute = buildRoute({
...CONFIG_PLUGIN,
@@ -31,11 +31,15 @@ export const testRoute = buildRoute({
},
},
handler: c => {
- new EmailModel(c).send({
- html: 'Test email
',
- to: 'ithereplay@gmail.com',
- subject: 'Test Email',
- });
+ // new EmailModel(c).send({
+ // html: 'Test email
',
+ // to: 'ithereplay@gmail.com',
+ // subject: 'Test Email',
+ // });
+
+ // throw new Error('Test error');
+
+ // c.get('log').warn('This is a test warn log');
return c.text('test');
},
diff --git a/packages/vitnode/src/app_admin/core/debug/page.tsx b/packages/vitnode/src/app_admin/core/debug/page.tsx
index 99c9a2ce5..1447ad4fa 100644
--- a/packages/vitnode/src/app_admin/core/debug/page.tsx
+++ b/packages/vitnode/src/app_admin/core/debug/page.tsx
@@ -1,9 +1,16 @@
import { getTranslations } from 'next-intl/server';
+import React from 'react';
import { I18nProvider } from '@/components/i18n-provider';
+import { DataTableSkeleton } from '@/components/table/data-table';
import { HeaderContent } from '@/components/ui/header-content';
import { ClearCacheAction } from '@/views/admin/views/core/debug/actions/clear-cache/clear-cache';
-import { DebugAdminView } from '@/views/admin/views/core/debug/debug-admin-view';
+
+const DebugAdminView = React.lazy(async () =>
+ import('@/views/admin/views/core/debug/debug-admin-view').then(module => ({
+ default: module.DebugAdminView,
+ })),
+);
export const generateMetadata = async () => {
const t = await getTranslations('admin.debug');
@@ -14,7 +21,9 @@ export const generateMetadata = async () => {
};
};
-export default async function Page() {
+export default async function Page(
+ props: React.ComponentProps,
+) {
const t = await getTranslations('admin.debug');
return (
@@ -24,7 +33,10 @@ export default async function Page() {
-
+
+ }>
+
+
);
diff --git a/packages/vitnode/src/app_admin/core/users/page.tsx b/packages/vitnode/src/app_admin/core/users/page.tsx
index 551042280..a78dc48d8 100644
--- a/packages/vitnode/src/app_admin/core/users/page.tsx
+++ b/packages/vitnode/src/app_admin/core/users/page.tsx
@@ -5,7 +5,12 @@ import React from 'react';
import { DataTableSkeleton } from '@/components/table/data-table';
import { HeaderContent } from '@/components/ui/header-content';
-import { UsersAdminView } from '@/views/admin/views/core/users/users-admin-view';
+
+const UsersAdminView = React.lazy(async () =>
+ import('@/views/admin/views/core/users/users-admin-view').then(module => ({
+ default: module.UsersAdminView,
+ })),
+);
export const generateMetadata = async (): Promise => {
const t = await getTranslations('admin.global.nav.users');
diff --git a/packages/vitnode/src/components/date-format.tsx b/packages/vitnode/src/components/date-format.tsx
index f85bde299..039c0480f 100644
--- a/packages/vitnode/src/components/date-format.tsx
+++ b/packages/vitnode/src/components/date-format.tsx
@@ -12,8 +12,10 @@ import {
export const DateFormat = ({
date,
updateInterval,
+ showFullDate,
}: {
date: Date | string;
+ showFullDate?: boolean;
updateInterval?: number;
}) => {
const dateToFormat = typeof date === 'string' ? new Date(date) : date;
@@ -34,6 +36,10 @@ export const DateFormat = ({
minute: 'numeric',
});
+ if (showFullDate) {
+ return fullDate;
+ }
+
// When date is < 7 days
if (now.getTime() - dateToFormat.getTime() < 604800000) {
return (
diff --git a/packages/vitnode/src/database/logs.ts b/packages/vitnode/src/database/logs.ts
index d2f67de1f..9f510e327 100644
--- a/packages/vitnode/src/database/logs.ts
+++ b/packages/vitnode/src/database/logs.ts
@@ -1,17 +1,14 @@
import { pgEnum, pgTable } from 'drizzle-orm/pg-core';
-import { core_users } from './users';
+export const coreLogsType = pgEnum('coreLogsType', ['warn', 'error', 'debug']);
-export const typeLogs = pgEnum('typeLogs', ['info', 'warn', 'error', 'debug']);
+export type CoreLogsType = (typeof coreLogsType.enumValues)[number];
export const core_logs = pgTable('core_logs', t => ({
id: t.serial().primaryKey(),
- pluginCode: t.varchar({ length: 255 }).notNull(),
- type: typeLogs().notNull().default('info'),
+ pluginId: t.varchar({ length: 255 }).notNull(),
+ type: coreLogsType().notNull(),
content: t.text().notNull(),
createdAt: t.timestamp().notNull().defaultNow(),
- userId: t.integer().references(() => core_users.id, {
- onDelete: 'set null',
- }),
- ipAddress: t.varchar({ length: 45 }).notNull().default(''),
+ ipAddress: t.varchar({ length: 45 }).notNull(),
})).enableRLS();
diff --git a/packages/vitnode/src/globals.css b/packages/vitnode/src/globals.css
index 507c9d21e..e2c711cdd 100644
--- a/packages/vitnode/src/globals.css
+++ b/packages/vitnode/src/globals.css
@@ -24,6 +24,7 @@
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
+ --color-warn: var(--warn);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
diff --git a/packages/vitnode/src/lib/fetcher-client.ts b/packages/vitnode/src/lib/fetcher-client.ts
index 8ebdadc75..a22588912 100644
--- a/packages/vitnode/src/lib/fetcher-client.ts
+++ b/packages/vitnode/src/lib/fetcher-client.ts
@@ -36,8 +36,10 @@ export async function fetcherClient<
args,
options,
withPagination = false,
+ prefixPath = '',
}: FetcherParams & {
options?: Omit;
+ prefixPath?: string;
withPagination?: boolean;
},
): Promise<
@@ -50,5 +52,6 @@ export async function fetcherClient<
args,
options,
withPagination,
+ prefixPath,
});
}
diff --git a/packages/vitnode/src/lib/fetcher.ts b/packages/vitnode/src/lib/fetcher.ts
index ee33935df..1a2a097f1 100644
--- a/packages/vitnode/src/lib/fetcher.ts
+++ b/packages/vitnode/src/lib/fetcher.ts
@@ -41,9 +41,11 @@ export async function fetcher<
options,
allowSaveCookies = false,
withPagination = false,
+ prefixPath = '',
}: FetcherParams & {
allowSaveCookies?: boolean;
options?: Omit;
+ prefixPath?: string;
withPagination?: boolean;
},
): Promise<
@@ -61,6 +63,7 @@ export async function fetcher<
args,
options,
withPagination,
+ prefixPath,
additionalHeaders: {
Cookie: cookie.toString(),
['user-agent']: nextInternalHeaders.get('user-agent') ?? 'node',
diff --git a/packages/vitnode/src/lib/fetcher/core.ts b/packages/vitnode/src/lib/fetcher/core.ts
index 5b69ccd26..505a73387 100644
--- a/packages/vitnode/src/lib/fetcher/core.ts
+++ b/packages/vitnode/src/lib/fetcher/core.ts
@@ -42,6 +42,7 @@ interface CoreFetcherOptions<
module: ModuleName;
options?: Omit;
path: SelectedPath;
+ prefixPath?: string;
withPagination?: boolean;
}
@@ -68,6 +69,7 @@ export async function coreFetcher<
options,
additionalHeaders = {},
withPagination = false,
+ prefixPath = '',
}: CoreFetcherOptions,
): Promise<
InferResponseType
@@ -90,7 +92,7 @@ export async function coreFetcher<
// Construct the base URL
const url = new URL(
- `/api/${pluginId}/${module}${formattedPath}`,
+ `/api/${pluginId}${prefixPath}/${module}${formattedPath}`,
CONFIG.backend.origin,
);
diff --git a/packages/vitnode/src/locales/en.json b/packages/vitnode/src/locales/en.json
index 0890d7c28..a3b9c9560 100644
--- a/packages/vitnode/src/locales/en.json
+++ b/packages/vitnode/src/locales/en.json
@@ -170,6 +170,19 @@
"success": "Cache cleared successfully.",
"confirm": "Yes, clear cache"
}
+ },
+ "logs": {
+ "title": "System Logs",
+ "id": "ID",
+ "created_at": "Created At",
+ "plugin": "Plugin",
+ "content": "Content",
+ "type": "Type",
+ "types": {
+ "warn": "Warning",
+ "error": "Error",
+ "debug": "Debug"
+ }
}
}
}
diff --git a/packages/vitnode/src/views/admin/views/core/debug/debug-admin-view.tsx b/packages/vitnode/src/views/admin/views/core/debug/debug-admin-view.tsx
index 53c4c0cd3..47f634998 100644
--- a/packages/vitnode/src/views/admin/views/core/debug/debug-admin-view.tsx
+++ b/packages/vitnode/src/views/admin/views/core/debug/debug-admin-view.tsx
@@ -1,3 +1,102 @@
-export const DebugAdminView = () => {
- return DebugAdminView
;
+import { TriangleAlertIcon, XIcon } from 'lucide-react';
+import { getTranslations } from 'next-intl/server';
+
+import { debugAdminModule } from '@/api/modules/admin/debug/debug.admin.module';
+import { DateFormat } from '@/components/date-format';
+import { DataTable } from '@/components/table/data-table';
+import { Badge } from '@/components/ui/badge';
+import { fetcher } from '@/lib/fetcher';
+
+export const DebugAdminView = async ({
+ searchParams,
+}: {
+ searchParams: Promise>;
+}) => {
+ const t = await getTranslations('admin.debug.logs');
+ const query = await searchParams;
+ const res = await fetcher(debugAdminModule, {
+ prefixPath: '/admin',
+ path: '/logs',
+ method: 'get',
+ module: 'debug',
+ args: {
+ query,
+ },
+ withPagination: true,
+ });
+ const data = await res.json();
+
+ return (
+ {
+ if (row.type === 'warn') {
+ return (
+
+ {t(`types.${row.type}`)}
+
+ );
+ }
+
+ if (row.type === 'error') {
+ return (
+
+ {t(`types.${row.type}`)}
+
+ );
+ }
+
+ return {t(`types.${row.type}`)};
+ },
+ },
+ {
+ id: 'pluginId',
+ label: t('plugin'),
+ className: 'w-48',
+ },
+ {
+ id: 'createdAt',
+ label: t('created_at'),
+ cell: ({ row }) => ,
+ },
+ {
+ id: 'content',
+ label: t('content'),
+ cell: ({ row }) => {
+ const CHARACTERS = 50;
+ const content = row.content;
+ const isLong = content.length > CHARACTERS;
+ const displayContent = isLong
+ ? content.slice(0, CHARACTERS) + '...'
+ : content;
+
+ return {displayContent};
+ },
+ },
+ {
+ id: 'actions',
+ label: '',
+ cell: ({ row }) => actions,
+ },
+ ]}
+ edges={data.edges.map(edge => ({ ...edge }))}
+ order={{
+ columns: ['createdAt', 'pluginId', 'type'],
+ defaultOrder: {
+ column: 'createdAt',
+ order: 'desc',
+ },
+ }}
+ pageInfo={data.pageInfo}
+ />
+ );
};
diff --git a/plugins/blog/src/api/modules/admin/admin.module.ts b/plugins/blog/src/api/modules/admin/admin.module.ts
new file mode 100644
index 000000000..e0290055d
--- /dev/null
+++ b/plugins/blog/src/api/modules/admin/admin.module.ts
@@ -0,0 +1,12 @@
+import { buildModule } from '@vitnode/core/api/lib/module';
+
+import { CONFIG_PLUGIN } from '../../../const';
+import { categoriesAdminModule } from './categories/categories.admin.module';
+import { postsAdminModule } from './posts/posts.admin.module';
+
+export const adminModule = buildModule({
+ ...CONFIG_PLUGIN,
+ name: 'admin',
+ modules: [categoriesAdminModule, postsAdminModule],
+ routes: [],
+});
diff --git a/plugins/blog/src/api/modules/admin/categories/categories.admin.module.ts b/plugins/blog/src/api/modules/admin/categories/categories.admin.module.ts
new file mode 100644
index 000000000..327be697b
--- /dev/null
+++ b/plugins/blog/src/api/modules/admin/categories/categories.admin.module.ts
@@ -0,0 +1,12 @@
+import { buildModule } from '@vitnode/core/api/lib/module';
+
+import { CONFIG_PLUGIN } from '../../../../const';
+import { createCategoryRoute } from './routes/create.route';
+import { deleteCategoryRoute } from './routes/delete.route';
+import { editCategoryRoute } from './routes/edit.route';
+
+export const categoriesAdminModule = buildModule({
+ ...CONFIG_PLUGIN,
+ name: 'categories',
+ routes: [createCategoryRoute, editCategoryRoute, deleteCategoryRoute],
+});
diff --git a/plugins/blog/src/api/modules/categories/routes/create.route.ts b/plugins/blog/src/api/modules/admin/categories/routes/create.route.ts
similarity index 100%
rename from plugins/blog/src/api/modules/categories/routes/create.route.ts
rename to plugins/blog/src/api/modules/admin/categories/routes/create.route.ts
diff --git a/plugins/blog/src/api/modules/categories/routes/delete.route.ts b/plugins/blog/src/api/modules/admin/categories/routes/delete.route.ts
similarity index 100%
rename from plugins/blog/src/api/modules/categories/routes/delete.route.ts
rename to plugins/blog/src/api/modules/admin/categories/routes/delete.route.ts
diff --git a/plugins/blog/src/api/modules/categories/routes/edit.route.ts b/plugins/blog/src/api/modules/admin/categories/routes/edit.route.ts
similarity index 100%
rename from plugins/blog/src/api/modules/categories/routes/edit.route.ts
rename to plugins/blog/src/api/modules/admin/categories/routes/edit.route.ts
diff --git a/plugins/blog/src/api/modules/admin/posts/posts.admin.module.ts b/plugins/blog/src/api/modules/admin/posts/posts.admin.module.ts
new file mode 100644
index 000000000..cbc093b4a
--- /dev/null
+++ b/plugins/blog/src/api/modules/admin/posts/posts.admin.module.ts
@@ -0,0 +1,12 @@
+import { buildModule } from '@vitnode/core/api/lib/module';
+
+import { CONFIG_PLUGIN } from '../../../../const';
+import { createPostRoute } from './routes/create.route';
+import { deletePostRoute } from './routes/delete.route';
+import { editPostRoute } from './routes/edit.route';
+
+export const postsAdminModule = buildModule({
+ ...CONFIG_PLUGIN,
+ name: 'posts',
+ routes: [editPostRoute, createPostRoute, deletePostRoute],
+});
diff --git a/plugins/blog/src/api/modules/posts/routes/create.route.ts b/plugins/blog/src/api/modules/admin/posts/routes/create.route.ts
similarity index 100%
rename from plugins/blog/src/api/modules/posts/routes/create.route.ts
rename to plugins/blog/src/api/modules/admin/posts/routes/create.route.ts
diff --git a/plugins/blog/src/api/modules/posts/routes/delete.route.ts b/plugins/blog/src/api/modules/admin/posts/routes/delete.route.ts
similarity index 100%
rename from plugins/blog/src/api/modules/posts/routes/delete.route.ts
rename to plugins/blog/src/api/modules/admin/posts/routes/delete.route.ts
diff --git a/plugins/blog/src/api/modules/posts/routes/edit.route.ts b/plugins/blog/src/api/modules/admin/posts/routes/edit.route.ts
similarity index 100%
rename from plugins/blog/src/api/modules/posts/routes/edit.route.ts
rename to plugins/blog/src/api/modules/admin/posts/routes/edit.route.ts
diff --git a/plugins/blog/src/api/modules/categories/categories.module.ts b/plugins/blog/src/api/modules/categories/categories.module.ts
index 65fc0c3d9..9868128b0 100644
--- a/plugins/blog/src/api/modules/categories/categories.module.ts
+++ b/plugins/blog/src/api/modules/categories/categories.module.ts
@@ -2,18 +2,10 @@ import { buildModule } from '@vitnode/core/api/lib/module';
import { CONFIG_PLUGIN } from '@/const';
-import { createCategoryRoute } from './routes/create.route';
-import { deleteCategoryRoute } from './routes/delete.route';
-import { editCategoryRoute } from './routes/edit.route';
import { categoriesRoute } from './routes/get.route';
export const categoriesModule = buildModule({
...CONFIG_PLUGIN,
name: 'categories',
- routes: [
- categoriesRoute,
- createCategoryRoute,
- editCategoryRoute,
- deleteCategoryRoute,
- ],
+ routes: [categoriesRoute],
});
diff --git a/plugins/blog/src/api/modules/posts/posts.module.ts b/plugins/blog/src/api/modules/posts/posts.module.ts
index e267437c8..dc74a95ac 100644
--- a/plugins/blog/src/api/modules/posts/posts.module.ts
+++ b/plugins/blog/src/api/modules/posts/posts.module.ts
@@ -2,13 +2,10 @@ import { buildModule } from '@vitnode/core/api/lib/module';
import { CONFIG_PLUGIN } from '@/const';
-import { createPostRoute } from './routes/create.route';
-import { deletePostRoute } from './routes/delete.route';
-import { editPostRoute } from './routes/edit.route';
import { postsRoute } from './routes/get.route';
export const postsModule = buildModule({
...CONFIG_PLUGIN,
name: 'posts',
- routes: [postsRoute, createPostRoute, editPostRoute, deletePostRoute],
+ routes: [postsRoute],
});
diff --git a/plugins/blog/src/app_admin/blog/categories/page.tsx b/plugins/blog/src/app_admin/blog/categories/page.tsx
index f7d85148c..a0ce4eae8 100644
--- a/plugins/blog/src/app_admin/blog/categories/page.tsx
+++ b/plugins/blog/src/app_admin/blog/categories/page.tsx
@@ -7,7 +7,12 @@ import { getTranslations } from 'next-intl/server';
import React from 'react';
import { ActionsCategoriesAdmin } from '@/views/admin/categories/actions/actions';
-import { CategoriesAdminView } from '@/views/admin/categories/categories-admin-view';
+
+const CategoriesAdminView = React.lazy(async () =>
+ import('@/views/admin/categories/categories-admin-view').then(mod => ({
+ default: mod.CategoriesAdminView,
+ })),
+);
export const generateMetadata = async (): Promise => {
const t = await getTranslations('@vitnode/blog.admin.nav');
diff --git a/plugins/blog/src/app_admin/blog/posts/page.tsx b/plugins/blog/src/app_admin/blog/posts/page.tsx
index 1b8872400..d5353ff54 100644
--- a/plugins/blog/src/app_admin/blog/posts/page.tsx
+++ b/plugins/blog/src/app_admin/blog/posts/page.tsx
@@ -7,7 +7,12 @@ import { getTranslations } from 'next-intl/server';
import React from 'react';
import { ActionsPostsAdmin } from '@/views/admin/posts/actions/actions';
-import { PostsAdminView } from '@/views/admin/posts/posts-admin-view';
+
+const PostsAdminView = React.lazy(async () =>
+ import('@/views/admin/posts/posts-admin-view').then(mod => ({
+ default: mod.PostsAdminView,
+ })),
+);
export const generateMetadata = async (): Promise => {
const t = await getTranslations('@vitnode/blog.admin.nav');
diff --git a/plugins/blog/src/config.api.ts b/plugins/blog/src/config.api.ts
index bc3ea3d3c..a30b0eb8d 100644
--- a/plugins/blog/src/config.api.ts
+++ b/plugins/blog/src/config.api.ts
@@ -2,12 +2,13 @@ import { buildApiPlugin } from '@vitnode/core/api/lib/plugin';
import { CONFIG_PLUGIN } from '@/const';
+import { adminModule } from './api/modules/admin/admin.module';
import { categoriesModule } from './api/modules/categories/categories.module';
import { postsModule } from './api/modules/posts/posts.module';
export const blogApiPlugin = () => {
return buildApiPlugin({
...CONFIG_PLUGIN,
- modules: [categoriesModule, postsModule],
+ modules: [adminModule, categoriesModule, postsModule],
});
};
diff --git a/plugins/blog/src/globals.css b/plugins/blog/src/globals.css
index 507c9d21e..e2c711cdd 100644
--- a/plugins/blog/src/globals.css
+++ b/plugins/blog/src/globals.css
@@ -24,6 +24,7 @@
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
+ --color-warn: var(--warn);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
diff --git a/plugins/blog/src/views/admin/categories/actions/create-edit/create-edit.tsx b/plugins/blog/src/views/admin/categories/actions/create-edit/create-edit.tsx
index 388ec66b5..770ca86b0 100644
--- a/plugins/blog/src/views/admin/categories/actions/create-edit/create-edit.tsx
+++ b/plugins/blog/src/views/admin/categories/actions/create-edit/create-edit.tsx
@@ -8,7 +8,7 @@ import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
import { z } from 'zod';
-import type { zodCreateCategorySchema } from '@/api/modules/categories/routes/create.route';
+import type { zodCreateCategorySchema } from '@/api/modules/admin/categories/routes/create.route';
import { createMutationApi, editMutationApi } from './mutation-api';
diff --git a/plugins/blog/src/views/admin/categories/actions/create-edit/mutation-api.ts b/plugins/blog/src/views/admin/categories/actions/create-edit/mutation-api.ts
index 67bcb138e..e68dfd31c 100644
--- a/plugins/blog/src/views/admin/categories/actions/create-edit/mutation-api.ts
+++ b/plugins/blog/src/views/admin/categories/actions/create-edit/mutation-api.ts
@@ -5,14 +5,15 @@ import type { z } from 'zod';
import { fetcher } from '@vitnode/core/lib/fetcher';
import { revalidatePath } from 'next/cache';
-import type { zodCreateCategorySchema } from '@/api/modules/categories/routes/create.route';
+import type { zodCreateCategorySchema } from '../../../../../api/modules/admin/categories/routes/create.route';
-import { categoriesModule } from '@/api/modules/categories/categories.module';
+import { categoriesAdminModule } from '../../../../../api/modules/admin/categories/categories.admin.module';
export const createMutationApi = async (
body: z.infer,
) => {
- const res = await fetcher(categoriesModule, {
+ const res = await fetcher(categoriesAdminModule, {
+ prefixPath: '/admin',
method: 'post',
module: 'categories',
path: '/',
@@ -35,7 +36,8 @@ export const editMutationApi = async ({
id,
...body
}: z.infer & { id: number }) => {
- const res = await fetcher(categoriesModule, {
+ const res = await fetcher(categoriesAdminModule, {
+ prefixPath: '/admin',
method: 'put',
module: 'categories',
path: '/{id}',
diff --git a/plugins/blog/src/views/admin/categories/row-actions/delete/mutation-api.ts b/plugins/blog/src/views/admin/categories/row-actions/delete/mutation-api.ts
index e0409aa9a..09fbf0d3c 100644
--- a/plugins/blog/src/views/admin/categories/row-actions/delete/mutation-api.ts
+++ b/plugins/blog/src/views/admin/categories/row-actions/delete/mutation-api.ts
@@ -3,10 +3,11 @@
import { fetcher } from '@vitnode/core/lib/fetcher';
import { revalidatePath } from 'next/cache';
-import { categoriesModule } from '@/api/modules/categories/categories.module';
+import { categoriesAdminModule } from '@/api/modules/admin/categories/categories.admin.module';
export const mutationApi = async (id: number) => {
- const res = await fetcher(categoriesModule, {
+ const res = await fetcher(categoriesAdminModule, {
+ prefixPath: '/admin',
method: 'delete',
path: '/{id}',
module: 'categories',
diff --git a/plugins/blog/src/views/admin/posts/actions/create-edit/mutation-api.ts b/plugins/blog/src/views/admin/posts/actions/create-edit/mutation-api.ts
index 9ef413f39..270e90ac8 100644
--- a/plugins/blog/src/views/admin/posts/actions/create-edit/mutation-api.ts
+++ b/plugins/blog/src/views/admin/posts/actions/create-edit/mutation-api.ts
@@ -5,14 +5,15 @@ import type { z } from 'zod';
import { fetcher } from '@vitnode/core/lib/fetcher';
import { revalidatePath } from 'next/cache';
-import type { zodCreatePostSchema } from '@/api/modules/posts/routes/create.route';
+import type { zodCreatePostSchema } from '@/api/modules/admin/posts/routes/create.route';
-import { postsModule } from '@/api/modules/posts/posts.module';
+import { postsAdminModule } from '@/api/modules/admin/posts/posts.admin.module';
export const createMutationApi = async (
body: z.infer,
) => {
- const res = await fetcher(postsModule, {
+ const res = await fetcher(postsAdminModule, {
+ prefixPath: '/admin',
method: 'post',
module: 'posts',
path: '/',
@@ -35,7 +36,8 @@ export const editMutationApi = async ({
id,
...body
}: z.infer & { id: number }) => {
- const res = await fetcher(postsModule, {
+ const res = await fetcher(postsAdminModule, {
+ prefixPath: '/admin',
method: 'put',
module: 'posts',
path: '/{id}',
diff --git a/plugins/blog/src/views/admin/posts/row-actions/delete/mutation-api.ts b/plugins/blog/src/views/admin/posts/row-actions/delete/mutation-api.ts
index a336e642d..937a3f6d0 100644
--- a/plugins/blog/src/views/admin/posts/row-actions/delete/mutation-api.ts
+++ b/plugins/blog/src/views/admin/posts/row-actions/delete/mutation-api.ts
@@ -3,10 +3,11 @@
import { fetcher } from '@vitnode/core/lib/fetcher';
import { revalidatePath } from 'next/cache';
-import { postsModule } from '@/api/modules/posts/posts.module';
+import { postsAdminModule } from '@/api/modules/admin/posts/posts.admin.module';
export const mutationApi = async (id: number) => {
- const res = await fetcher(postsModule, {
+ const res = await fetcher(postsAdminModule, {
+ prefixPath: '/admin',
method: 'delete',
path: '/{id}',
module: 'posts',