sveltekit-admin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -0
- package/dist/admin.d.ts +227 -0
- package/dist/admin.js +369 -0
- package/dist/components/AdminForm.svelte +423 -0
- package/dist/components/AdminForm.svelte.d.ts +30 -0
- package/dist/components/AdminLayout.svelte +328 -0
- package/dist/components/AdminLayout.svelte.d.ts +20 -0
- package/dist/components/DataTable.svelte +573 -0
- package/dist/components/DataTable.svelte.d.ts +25 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +3 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +16 -0
- package/dist/server/auth/guard.d.ts +36 -0
- package/dist/server/auth/guard.js +38 -0
- package/dist/server/auth/index.d.ts +1 -0
- package/dist/server/auth/index.js +1 -0
- package/dist/server/crud/index.d.ts +1 -0
- package/dist/server/crud/index.js +1 -0
- package/dist/server/crud/operations.d.ts +87 -0
- package/dist/server/crud/operations.js +276 -0
- package/dist/server/introspection/index.d.ts +1 -0
- package/dist/server/introspection/index.js +1 -0
- package/dist/server/introspection/parser.d.ts +51 -0
- package/dist/server/introspection/parser.js +193 -0
- package/package.json +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# sveltekit-admin
|
|
2
|
+
|
|
3
|
+
🎛️ A Django-like admin panel for SvelteKit applications with Prisma and better-auth.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🔍 **Auto-introspection** of Prisma schema
|
|
11
|
+
- 📝 **CRUD operations** auto-generated for all models
|
|
12
|
+
- 🔐 **better-auth integration** for admin authentication
|
|
13
|
+
- 🎨 **Standalone UI** - no Tailwind or other CSS framework required
|
|
14
|
+
- ⚡ **Zero-config** - just add the plugin and you're ready
|
|
15
|
+
- 🔧 **Customizable** - hide fields, set readonly, custom labels
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install sveltekit-admin
|
|
21
|
+
# or
|
|
22
|
+
bun add sveltekit-admin
|
|
23
|
+
# or
|
|
24
|
+
pnpm add sveltekit-admin
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Add the Vite plugin
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// vite.config.ts
|
|
33
|
+
import { sveltekit } from '@sveltejs/kit/vite';
|
|
34
|
+
import { svelteKitAdmin } from 'sveltekit-admin/plugin';
|
|
35
|
+
import { defineConfig } from 'vite';
|
|
36
|
+
|
|
37
|
+
export default defineConfig({
|
|
38
|
+
plugins: [
|
|
39
|
+
sveltekit(),
|
|
40
|
+
svelteKitAdmin({
|
|
41
|
+
prismaSchemaPath: './prisma/schema.prisma',
|
|
42
|
+
basePath: '/admin',
|
|
43
|
+
auth: {
|
|
44
|
+
provider: 'better-auth',
|
|
45
|
+
adminRole: 'admin'
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Add the auth hook (optional, for protected admin)
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// src/hooks.server.ts
|
|
56
|
+
import { createAdminHandle } from 'sveltekit-admin';
|
|
57
|
+
import { sequence } from '@sveltejs/kit/hooks';
|
|
58
|
+
|
|
59
|
+
const adminHandle = createAdminHandle({
|
|
60
|
+
basePath: '/admin',
|
|
61
|
+
auth: {
|
|
62
|
+
provider: 'better-auth',
|
|
63
|
+
adminRole: 'admin'
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export const handle = sequence(
|
|
68
|
+
// your auth handle first
|
|
69
|
+
adminHandle
|
|
70
|
+
);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 3. Access your admin panel
|
|
74
|
+
|
|
75
|
+
Navigate to `/admin` and you'll see:
|
|
76
|
+
- Dashboard with model statistics
|
|
77
|
+
- List views with pagination, search, and sorting
|
|
78
|
+
- Create/Edit forms auto-generated from your Prisma schema
|
|
79
|
+
- Delete with confirmation
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
svelteKitAdmin({
|
|
85
|
+
// Path to your Prisma schema (default: './prisma/schema.prisma')
|
|
86
|
+
prismaSchemaPath: './prisma/schema.prisma',
|
|
87
|
+
|
|
88
|
+
// Base path for admin routes (default: '/admin')
|
|
89
|
+
basePath: '/admin',
|
|
90
|
+
|
|
91
|
+
// Authentication configuration
|
|
92
|
+
auth: {
|
|
93
|
+
provider: 'better-auth',
|
|
94
|
+
adminRole: 'admin', // Role required to access admin
|
|
95
|
+
// Or custom check function:
|
|
96
|
+
adminCheck: async (user) => user.isAdmin === true
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// Per-model configuration
|
|
100
|
+
models: {
|
|
101
|
+
User: {
|
|
102
|
+
// Fields to hide from all views
|
|
103
|
+
hidden: ['password', 'hashedPassword'],
|
|
104
|
+
// Fields that cannot be edited
|
|
105
|
+
readonly: ['id', 'createdAt', 'updatedAt'],
|
|
106
|
+
// Fields to show in list view (default: auto-detect)
|
|
107
|
+
listFields: ['email', 'name', 'role', 'createdAt'],
|
|
108
|
+
// Custom label for the model
|
|
109
|
+
label: 'Users',
|
|
110
|
+
// Icon name (Lucide icon)
|
|
111
|
+
icon: 'users'
|
|
112
|
+
},
|
|
113
|
+
Session: {
|
|
114
|
+
// Completely exclude this model from admin
|
|
115
|
+
hidden: true
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
// Models to exclude from admin
|
|
120
|
+
exclude: ['Session', 'VerificationToken'],
|
|
121
|
+
|
|
122
|
+
// Custom branding
|
|
123
|
+
branding: {
|
|
124
|
+
title: 'My Admin',
|
|
125
|
+
logo: '/logo.svg',
|
|
126
|
+
primaryColor: '#6366f1'
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Components
|
|
132
|
+
|
|
133
|
+
You can also use the admin components directly in your own pages:
|
|
134
|
+
|
|
135
|
+
```svelte
|
|
136
|
+
<script>
|
|
137
|
+
import { AdminLayout, DataTable, AdminForm } from 'sveltekit-admin/components';
|
|
138
|
+
</script>
|
|
139
|
+
|
|
140
|
+
<AdminLayout title="Custom Admin" models={[...]}>
|
|
141
|
+
<DataTable
|
|
142
|
+
data={users}
|
|
143
|
+
columns={[
|
|
144
|
+
{ key: 'email', label: 'Email', sortable: true },
|
|
145
|
+
{ key: 'name', label: 'Name', sortable: true }
|
|
146
|
+
]}
|
|
147
|
+
basePath="/admin"
|
|
148
|
+
modelName="User"
|
|
149
|
+
/>
|
|
150
|
+
</AdminLayout>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Prisma Schema Introspection
|
|
154
|
+
|
|
155
|
+
The admin automatically parses your Prisma schema and:
|
|
156
|
+
|
|
157
|
+
- Extracts all models and their fields
|
|
158
|
+
- Detects field types and generates appropriate form inputs
|
|
159
|
+
- Handles relations (1-1, 1-N, N-N)
|
|
160
|
+
- Respects field attributes (@id, @unique, @default, @updatedAt)
|
|
161
|
+
- Hides sensitive fields by name pattern (password, hash, secret)
|
|
162
|
+
|
|
163
|
+
## Requirements
|
|
164
|
+
|
|
165
|
+
- SvelteKit 2.x
|
|
166
|
+
- Svelte 5.x
|
|
167
|
+
- Prisma 5.x or 6.x
|
|
168
|
+
- better-auth 1.x (for authentication)
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit Admin - Core Admin Factory
|
|
3
|
+
* Creates all the necessary handlers for the admin panel
|
|
4
|
+
*/
|
|
5
|
+
import { type PrismaSchema, type PrismaModel } from './server/introspection/parser.js';
|
|
6
|
+
export interface AdminConfig {
|
|
7
|
+
/** Prisma client instance */
|
|
8
|
+
prisma: any;
|
|
9
|
+
/** Path to Prisma schema file */
|
|
10
|
+
schemaPath?: string;
|
|
11
|
+
/** Parsed schema (alternative to schemaPath) */
|
|
12
|
+
schema?: PrismaSchema;
|
|
13
|
+
/** Base path for admin (default: /admin) */
|
|
14
|
+
basePath?: string;
|
|
15
|
+
/** Models to exclude */
|
|
16
|
+
exclude?: string[];
|
|
17
|
+
/** Per-model configuration */
|
|
18
|
+
models?: Record<string, {
|
|
19
|
+
hidden?: string[];
|
|
20
|
+
readonly?: string[];
|
|
21
|
+
listFields?: string[];
|
|
22
|
+
label?: string;
|
|
23
|
+
}>;
|
|
24
|
+
/** Branding options */
|
|
25
|
+
branding?: {
|
|
26
|
+
title?: string;
|
|
27
|
+
logo?: string;
|
|
28
|
+
primaryColor?: string;
|
|
29
|
+
};
|
|
30
|
+
/** Auth check function */
|
|
31
|
+
checkAdmin?: (user: unknown) => boolean | Promise<boolean>;
|
|
32
|
+
/** Admin role name (if using default check) */
|
|
33
|
+
adminRole?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface AdminContext {
|
|
36
|
+
config: AdminConfig;
|
|
37
|
+
schema: PrismaSchema;
|
|
38
|
+
models: PrismaModel[];
|
|
39
|
+
getModel: (name: string) => PrismaModel | undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create admin context with all necessary data
|
|
43
|
+
*/
|
|
44
|
+
export declare function createAdmin(config: AdminConfig): AdminContext;
|
|
45
|
+
/**
|
|
46
|
+
* Layout data loader - provides models list and config to layout
|
|
47
|
+
*/
|
|
48
|
+
export declare function createLayoutLoad(ctx: AdminContext): ({ locals }: {
|
|
49
|
+
locals: any;
|
|
50
|
+
}) => Promise<{
|
|
51
|
+
models: {
|
|
52
|
+
name: string;
|
|
53
|
+
label: string;
|
|
54
|
+
}[];
|
|
55
|
+
user: {
|
|
56
|
+
name: any;
|
|
57
|
+
email: any;
|
|
58
|
+
} | undefined;
|
|
59
|
+
config: {
|
|
60
|
+
basePath: string;
|
|
61
|
+
branding: {
|
|
62
|
+
title: string;
|
|
63
|
+
logo: string | undefined;
|
|
64
|
+
primaryColor: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Dashboard data loader - provides model counts
|
|
70
|
+
*/
|
|
71
|
+
export declare function createDashboardLoad(ctx: AdminContext): () => Promise<{
|
|
72
|
+
models: {
|
|
73
|
+
name: string;
|
|
74
|
+
label: string;
|
|
75
|
+
count: number;
|
|
76
|
+
}[];
|
|
77
|
+
stats: {
|
|
78
|
+
totalRecords: number;
|
|
79
|
+
modelsCount: number;
|
|
80
|
+
};
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Model list data loader
|
|
84
|
+
*/
|
|
85
|
+
export declare function createModelListLoad(ctx: AdminContext): ({ params, url }: {
|
|
86
|
+
params: {
|
|
87
|
+
model: string;
|
|
88
|
+
};
|
|
89
|
+
url: URL;
|
|
90
|
+
}) => Promise<{
|
|
91
|
+
model: {
|
|
92
|
+
name: string;
|
|
93
|
+
label: string;
|
|
94
|
+
fields: {
|
|
95
|
+
name: string;
|
|
96
|
+
type: string;
|
|
97
|
+
label: string;
|
|
98
|
+
}[];
|
|
99
|
+
primaryKey: string;
|
|
100
|
+
};
|
|
101
|
+
items: unknown[];
|
|
102
|
+
total: number;
|
|
103
|
+
page: number;
|
|
104
|
+
perPage: number;
|
|
105
|
+
orderBy: string;
|
|
106
|
+
orderDir: "asc" | "desc";
|
|
107
|
+
search: string;
|
|
108
|
+
config: {
|
|
109
|
+
basePath: string;
|
|
110
|
+
hidden: string[];
|
|
111
|
+
listFields: string[] | undefined;
|
|
112
|
+
};
|
|
113
|
+
}>;
|
|
114
|
+
/**
|
|
115
|
+
* Model create page loader
|
|
116
|
+
*/
|
|
117
|
+
export declare function createModelNewLoad(ctx: AdminContext): ({ params }: {
|
|
118
|
+
params: {
|
|
119
|
+
model: string;
|
|
120
|
+
};
|
|
121
|
+
}) => Promise<{
|
|
122
|
+
model: {
|
|
123
|
+
name: string;
|
|
124
|
+
label: string;
|
|
125
|
+
fields: {
|
|
126
|
+
name: string;
|
|
127
|
+
type: string;
|
|
128
|
+
required: boolean;
|
|
129
|
+
label: string;
|
|
130
|
+
}[];
|
|
131
|
+
};
|
|
132
|
+
config: {
|
|
133
|
+
basePath: string;
|
|
134
|
+
hidden: string[];
|
|
135
|
+
readonly: string[];
|
|
136
|
+
};
|
|
137
|
+
relationOptions: Record<string, {
|
|
138
|
+
id: string | number;
|
|
139
|
+
label: string;
|
|
140
|
+
}[]>;
|
|
141
|
+
}>;
|
|
142
|
+
/**
|
|
143
|
+
* Model create action
|
|
144
|
+
*/
|
|
145
|
+
export declare function createModelNewAction(ctx: AdminContext): ({ params, request }: {
|
|
146
|
+
params: {
|
|
147
|
+
model: string;
|
|
148
|
+
};
|
|
149
|
+
request: Request;
|
|
150
|
+
}) => Promise<{
|
|
151
|
+
success: boolean;
|
|
152
|
+
error?: undefined;
|
|
153
|
+
fieldErrors?: undefined;
|
|
154
|
+
} | {
|
|
155
|
+
success: boolean;
|
|
156
|
+
error: any;
|
|
157
|
+
fieldErrors: {};
|
|
158
|
+
}>;
|
|
159
|
+
/**
|
|
160
|
+
* Model edit page loader
|
|
161
|
+
*/
|
|
162
|
+
export declare function createModelEditLoad(ctx: AdminContext): ({ params }: {
|
|
163
|
+
params: {
|
|
164
|
+
model: string;
|
|
165
|
+
id: string;
|
|
166
|
+
};
|
|
167
|
+
}) => Promise<{
|
|
168
|
+
model: {
|
|
169
|
+
name: string;
|
|
170
|
+
label: string;
|
|
171
|
+
primaryKey: string;
|
|
172
|
+
fields: {
|
|
173
|
+
name: string;
|
|
174
|
+
type: string;
|
|
175
|
+
required: boolean;
|
|
176
|
+
label: string;
|
|
177
|
+
}[];
|
|
178
|
+
};
|
|
179
|
+
item: {};
|
|
180
|
+
config: {
|
|
181
|
+
basePath: string;
|
|
182
|
+
hidden: string[];
|
|
183
|
+
readonly: string[];
|
|
184
|
+
};
|
|
185
|
+
relationOptions: Record<string, {
|
|
186
|
+
id: string | number;
|
|
187
|
+
label: string;
|
|
188
|
+
}[]>;
|
|
189
|
+
}>;
|
|
190
|
+
/**
|
|
191
|
+
* Model update action
|
|
192
|
+
*/
|
|
193
|
+
export declare function createModelEditAction(ctx: AdminContext): ({ params, request }: {
|
|
194
|
+
params: {
|
|
195
|
+
model: string;
|
|
196
|
+
id: string;
|
|
197
|
+
};
|
|
198
|
+
request: Request;
|
|
199
|
+
}) => Promise<{
|
|
200
|
+
success: boolean;
|
|
201
|
+
error?: undefined;
|
|
202
|
+
} | {
|
|
203
|
+
success: boolean;
|
|
204
|
+
error: any;
|
|
205
|
+
}>;
|
|
206
|
+
/**
|
|
207
|
+
* Model delete action
|
|
208
|
+
*/
|
|
209
|
+
export declare function createModelDeleteAction(ctx: AdminContext): ({ params, request }: {
|
|
210
|
+
params: {
|
|
211
|
+
model: string;
|
|
212
|
+
};
|
|
213
|
+
request: Request;
|
|
214
|
+
}) => Promise<{
|
|
215
|
+
success: boolean;
|
|
216
|
+
error?: undefined;
|
|
217
|
+
} | {
|
|
218
|
+
success: boolean;
|
|
219
|
+
error: any;
|
|
220
|
+
}>;
|
|
221
|
+
/**
|
|
222
|
+
* Auth guard hook
|
|
223
|
+
*/
|
|
224
|
+
export declare function createAdminGuard(ctx: AdminContext): ({ event, resolve }: {
|
|
225
|
+
event: any;
|
|
226
|
+
resolve: Function;
|
|
227
|
+
}) => Promise<any>;
|