sveltekit-admin 0.2.0 → 0.5.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 +80 -2
- package/dist/index.d.ts +2 -7
- package/dist/index.js +2 -13
- package/dist/server/auth.d.ts +7 -0
- package/dist/server/auth.js +19 -0
- package/dist/server/data.d.ts +38 -0
- package/dist/server/data.js +116 -0
- package/dist/server/handler.d.ts +123 -4
- package/dist/server/handler.js +590 -819
- package/dist/server/introspection/parser.d.ts +19 -12
- package/dist/server/introspection/parser.js +71 -61
- package/dist/server/introspection/relations.d.ts +49 -0
- package/dist/server/introspection/relations.js +128 -0
- package/dist/server/query/filterDetection.d.ts +71 -0
- package/dist/server/query/filterDetection.js +153 -0
- package/dist/server/query/listQuery.d.ts +89 -0
- package/dist/server/query/listQuery.js +428 -0
- package/dist/server/query/urls.d.ts +33 -0
- package/dist/server/query/urls.js +58 -0
- package/dist/server/router.d.ts +6 -0
- package/dist/server/router.js +27 -0
- package/dist/server/views/Dashboard.svelte +29 -0
- package/dist/server/views/Dashboard.svelte.d.ts +15 -0
- package/dist/server/views/FieldInput.svelte +63 -0
- package/dist/server/views/FieldInput.svelte.d.ts +9 -0
- package/dist/server/views/Form.svelte +127 -0
- package/dist/server/views/Form.svelte.d.ts +12 -0
- package/dist/server/views/Layout.svelte +78 -0
- package/dist/server/views/Layout.svelte.d.ts +13 -0
- package/dist/server/views/List.svelte +240 -0
- package/dist/server/views/List.svelte.d.ts +27 -0
- package/dist/server/views/ListFilters.svelte +257 -0
- package/dist/server/views/ListFilters.svelte.d.ts +18 -0
- package/dist/server/views/ModelCard.svelte +11 -0
- package/dist/server/views/ModelCard.svelte.d.ts +8 -0
- package/dist/server/views/NotFound.svelte +7 -0
- package/dist/server/views/NotFound.svelte.d.ts +7 -0
- package/dist/server/views/RelatedBlock.svelte +74 -0
- package/dist/server/views/RelatedBlock.svelte.d.ts +11 -0
- package/dist/server/views/RelationCheckboxes.svelte +53 -0
- package/dist/server/views/RelationCheckboxes.svelte.d.ts +9 -0
- package/dist/server/views/RelationSelect.svelte +53 -0
- package/dist/server/views/RelationSelect.svelte.d.ts +12 -0
- package/dist/server/views/StatCard.svelte +18 -0
- package/dist/server/views/StatCard.svelte.d.ts +8 -0
- package/dist/server/views/html.d.ts +5 -0
- package/dist/server/views/html.js +41 -0
- package/dist/server/views/theme.d.ts +1 -0
- package/dist/server/views/theme.js +484 -0
- package/dist/server/views/types.d.ts +57 -0
- package/dist/server/views/types.js +1 -0
- package/package.json +24 -26
- package/dist/admin.d.ts +0 -227
- package/dist/admin.js +0 -369
- package/dist/components/AdminForm.svelte +0 -423
- package/dist/components/AdminForm.svelte.d.ts +0 -30
- package/dist/components/AdminLayout.svelte +0 -328
- package/dist/components/AdminLayout.svelte.d.ts +0 -20
- package/dist/components/DataTable.svelte +0 -573
- package/dist/components/DataTable.svelte.d.ts +0 -25
- package/dist/components/index.d.ts +0 -3
- package/dist/components/index.js +0 -3
- package/dist/server/auth/guard.d.ts +0 -36
- package/dist/server/auth/guard.js +0 -38
- package/dist/server/auth/index.d.ts +0 -1
- package/dist/server/auth/index.js +0 -1
- package/dist/server/crud/index.d.ts +0 -1
- package/dist/server/crud/index.js +0 -1
- package/dist/server/crud/operations.d.ts +0 -87
- package/dist/server/crud/operations.js +0 -276
- package/dist/server/introspection/index.d.ts +0 -1
- package/dist/server/introspection/index.js +0 -1
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CRUD Operations Generator
|
|
3
|
-
* Creates type-safe Prisma operations for admin panel
|
|
4
|
-
*/
|
|
5
|
-
import type { PrismaModel } from '../introspection/parser.js';
|
|
6
|
-
export interface ListOptions {
|
|
7
|
-
page?: number;
|
|
8
|
-
perPage?: number;
|
|
9
|
-
search?: string;
|
|
10
|
-
searchFields?: string[];
|
|
11
|
-
orderBy?: string;
|
|
12
|
-
orderDir?: 'asc' | 'desc';
|
|
13
|
-
filters?: Record<string, unknown>;
|
|
14
|
-
}
|
|
15
|
-
export interface ListResult<T> {
|
|
16
|
-
items: T[];
|
|
17
|
-
total: number;
|
|
18
|
-
page: number;
|
|
19
|
-
perPage: number;
|
|
20
|
-
totalPages: number;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Build a Prisma where clause for searching
|
|
24
|
-
*/
|
|
25
|
-
export declare function buildSearchWhere(search: string | undefined, searchFields: string[], model: PrismaModel): Record<string, unknown> | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* Build filter conditions from query params
|
|
28
|
-
*/
|
|
29
|
-
export declare function buildFilterWhere(filters: Record<string, unknown> | undefined, model: PrismaModel): Record<string, unknown>;
|
|
30
|
-
/**
|
|
31
|
-
* Create list operation config
|
|
32
|
-
*/
|
|
33
|
-
export declare function createListOperation(model: PrismaModel): {
|
|
34
|
-
modelName: string;
|
|
35
|
-
searchableFields: string[];
|
|
36
|
-
defaultOrderBy: string;
|
|
37
|
-
execute<T>(prisma: {
|
|
38
|
-
[key: string]: {
|
|
39
|
-
findMany: Function;
|
|
40
|
-
count: Function;
|
|
41
|
-
};
|
|
42
|
-
}, options?: ListOptions): Promise<ListResult<T>>;
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Create get single record operation
|
|
46
|
-
*/
|
|
47
|
-
export declare function createGetOperation(model: PrismaModel): {
|
|
48
|
-
modelName: string;
|
|
49
|
-
execute<T>(prisma: {
|
|
50
|
-
[key: string]: {
|
|
51
|
-
findUnique: Function;
|
|
52
|
-
};
|
|
53
|
-
}, id: string | number): Promise<T | null>;
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Create create operation
|
|
57
|
-
*/
|
|
58
|
-
export declare function createCreateOperation(model: PrismaModel): {
|
|
59
|
-
modelName: string;
|
|
60
|
-
execute<T>(prisma: {
|
|
61
|
-
[key: string]: {
|
|
62
|
-
create: Function;
|
|
63
|
-
};
|
|
64
|
-
}, data: Record<string, unknown>): Promise<T>;
|
|
65
|
-
};
|
|
66
|
-
/**
|
|
67
|
-
* Create update operation
|
|
68
|
-
*/
|
|
69
|
-
export declare function createUpdateOperation(model: PrismaModel): {
|
|
70
|
-
modelName: string;
|
|
71
|
-
execute<T>(prisma: {
|
|
72
|
-
[key: string]: {
|
|
73
|
-
update: Function;
|
|
74
|
-
};
|
|
75
|
-
}, id: string | number, data: Record<string, unknown>): Promise<T>;
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Create delete operation
|
|
79
|
-
*/
|
|
80
|
-
export declare function createDeleteOperation(model: PrismaModel): {
|
|
81
|
-
modelName: string;
|
|
82
|
-
execute(prisma: {
|
|
83
|
-
[key: string]: {
|
|
84
|
-
delete: Function;
|
|
85
|
-
};
|
|
86
|
-
}, id: string | number): Promise<void>;
|
|
87
|
-
};
|
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CRUD Operations Generator
|
|
3
|
-
* Creates type-safe Prisma operations for admin panel
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Build a Prisma where clause for searching
|
|
7
|
-
*/
|
|
8
|
-
export function buildSearchWhere(search, searchFields, model) {
|
|
9
|
-
if (!search || searchFields.length === 0)
|
|
10
|
-
return undefined;
|
|
11
|
-
const stringFields = searchFields.filter(fieldName => {
|
|
12
|
-
const field = model.fields.find(f => f.name === fieldName);
|
|
13
|
-
return field?.type === 'String';
|
|
14
|
-
});
|
|
15
|
-
if (stringFields.length === 0)
|
|
16
|
-
return undefined;
|
|
17
|
-
return {
|
|
18
|
-
OR: stringFields.map(field => ({
|
|
19
|
-
[field]: {
|
|
20
|
-
contains: search,
|
|
21
|
-
mode: 'insensitive'
|
|
22
|
-
}
|
|
23
|
-
}))
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Build filter conditions from query params
|
|
28
|
-
*/
|
|
29
|
-
export function buildFilterWhere(filters, model) {
|
|
30
|
-
if (!filters)
|
|
31
|
-
return {};
|
|
32
|
-
const where = {};
|
|
33
|
-
for (const [key, value] of Object.entries(filters)) {
|
|
34
|
-
if (value === undefined || value === null || value === '')
|
|
35
|
-
continue;
|
|
36
|
-
const field = model.fields.find(f => f.name === key);
|
|
37
|
-
if (!field)
|
|
38
|
-
continue;
|
|
39
|
-
// Handle different field types
|
|
40
|
-
switch (field.type) {
|
|
41
|
-
case 'String':
|
|
42
|
-
where[key] = { contains: String(value), mode: 'insensitive' };
|
|
43
|
-
break;
|
|
44
|
-
case 'Int':
|
|
45
|
-
case 'Float':
|
|
46
|
-
case 'Decimal':
|
|
47
|
-
case 'BigInt':
|
|
48
|
-
where[key] = Number(value);
|
|
49
|
-
break;
|
|
50
|
-
case 'Boolean':
|
|
51
|
-
where[key] = value === 'true' || value === true;
|
|
52
|
-
break;
|
|
53
|
-
case 'DateTime':
|
|
54
|
-
// Support date range filters
|
|
55
|
-
if (typeof value === 'object' && value !== null) {
|
|
56
|
-
const dateFilter = {};
|
|
57
|
-
if ('from' in value)
|
|
58
|
-
dateFilter.gte = new Date(value.from);
|
|
59
|
-
if ('to' in value)
|
|
60
|
-
dateFilter.lte = new Date(value.to);
|
|
61
|
-
where[key] = dateFilter;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
where[key] = new Date(String(value));
|
|
65
|
-
}
|
|
66
|
-
break;
|
|
67
|
-
default:
|
|
68
|
-
// For enums and relations
|
|
69
|
-
where[key] = value;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return where;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Create list operation config
|
|
76
|
-
*/
|
|
77
|
-
export function createListOperation(model) {
|
|
78
|
-
const searchableFields = model.fields
|
|
79
|
-
.filter(f => f.type === 'String' && !f.relation)
|
|
80
|
-
.map(f => f.name);
|
|
81
|
-
return {
|
|
82
|
-
modelName: model.name,
|
|
83
|
-
searchableFields,
|
|
84
|
-
defaultOrderBy: model.primaryKey || 'id',
|
|
85
|
-
async execute(prisma, options = {}) {
|
|
86
|
-
const { page = 1, perPage = 20, search, searchFields = searchableFields, orderBy = model.primaryKey || 'id', orderDir = 'desc', filters } = options;
|
|
87
|
-
const modelKey = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
88
|
-
const prismaModel = prisma[modelKey];
|
|
89
|
-
if (!prismaModel) {
|
|
90
|
-
throw new Error(`Model ${model.name} not found in Prisma client`);
|
|
91
|
-
}
|
|
92
|
-
// Build where clause
|
|
93
|
-
const searchWhere = buildSearchWhere(search, searchFields, model);
|
|
94
|
-
const filterWhere = buildFilterWhere(filters, model);
|
|
95
|
-
const where = {
|
|
96
|
-
...filterWhere,
|
|
97
|
-
...(searchWhere ? searchWhere : {})
|
|
98
|
-
};
|
|
99
|
-
// Build include for relations (limit depth)
|
|
100
|
-
const include = buildInclude(model);
|
|
101
|
-
// Execute queries
|
|
102
|
-
const [items, total] = await Promise.all([
|
|
103
|
-
prismaModel.findMany({
|
|
104
|
-
where,
|
|
105
|
-
include,
|
|
106
|
-
orderBy: { [orderBy]: orderDir },
|
|
107
|
-
skip: (page - 1) * perPage,
|
|
108
|
-
take: perPage
|
|
109
|
-
}),
|
|
110
|
-
prismaModel.count({ where })
|
|
111
|
-
]);
|
|
112
|
-
return {
|
|
113
|
-
items: items,
|
|
114
|
-
total,
|
|
115
|
-
page,
|
|
116
|
-
perPage,
|
|
117
|
-
totalPages: Math.ceil(total / perPage)
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Create get single record operation
|
|
124
|
-
*/
|
|
125
|
-
export function createGetOperation(model) {
|
|
126
|
-
return {
|
|
127
|
-
modelName: model.name,
|
|
128
|
-
async execute(prisma, id) {
|
|
129
|
-
const modelKey = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
130
|
-
const prismaModel = prisma[modelKey];
|
|
131
|
-
if (!prismaModel) {
|
|
132
|
-
throw new Error(`Model ${model.name} not found in Prisma client`);
|
|
133
|
-
}
|
|
134
|
-
const primaryKey = model.primaryKey || 'id';
|
|
135
|
-
const include = buildInclude(model);
|
|
136
|
-
// Convert ID to correct type
|
|
137
|
-
const pkField = model.fields.find(f => f.name === primaryKey);
|
|
138
|
-
const typedId = pkField?.type === 'Int' ? parseInt(String(id)) : id;
|
|
139
|
-
return prismaModel.findUnique({
|
|
140
|
-
where: { [primaryKey]: typedId },
|
|
141
|
-
include
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Create create operation
|
|
148
|
-
*/
|
|
149
|
-
export function createCreateOperation(model) {
|
|
150
|
-
return {
|
|
151
|
-
modelName: model.name,
|
|
152
|
-
async execute(prisma, data) {
|
|
153
|
-
const modelKey = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
154
|
-
const prismaModel = prisma[modelKey];
|
|
155
|
-
if (!prismaModel) {
|
|
156
|
-
throw new Error(`Model ${model.name} not found in Prisma client`);
|
|
157
|
-
}
|
|
158
|
-
// Process data - handle relations
|
|
159
|
-
const processedData = processInputData(data, model);
|
|
160
|
-
return prismaModel.create({
|
|
161
|
-
data: processedData
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Create update operation
|
|
168
|
-
*/
|
|
169
|
-
export function createUpdateOperation(model) {
|
|
170
|
-
return {
|
|
171
|
-
modelName: model.name,
|
|
172
|
-
async execute(prisma, id, data) {
|
|
173
|
-
const modelKey = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
174
|
-
const prismaModel = prisma[modelKey];
|
|
175
|
-
if (!prismaModel) {
|
|
176
|
-
throw new Error(`Model ${model.name} not found in Prisma client`);
|
|
177
|
-
}
|
|
178
|
-
const primaryKey = model.primaryKey || 'id';
|
|
179
|
-
const pkField = model.fields.find(f => f.name === primaryKey);
|
|
180
|
-
const typedId = pkField?.type === 'Int' ? parseInt(String(id)) : id;
|
|
181
|
-
// Process data - handle relations
|
|
182
|
-
const processedData = processInputData(data, model);
|
|
183
|
-
return prismaModel.update({
|
|
184
|
-
where: { [primaryKey]: typedId },
|
|
185
|
-
data: processedData
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Create delete operation
|
|
192
|
-
*/
|
|
193
|
-
export function createDeleteOperation(model) {
|
|
194
|
-
return {
|
|
195
|
-
modelName: model.name,
|
|
196
|
-
async execute(prisma, id) {
|
|
197
|
-
const modelKey = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
198
|
-
const prismaModel = prisma[modelKey];
|
|
199
|
-
if (!prismaModel) {
|
|
200
|
-
throw new Error(`Model ${model.name} not found in Prisma client`);
|
|
201
|
-
}
|
|
202
|
-
const primaryKey = model.primaryKey || 'id';
|
|
203
|
-
const pkField = model.fields.find(f => f.name === primaryKey);
|
|
204
|
-
const typedId = pkField?.type === 'Int' ? parseInt(String(id)) : id;
|
|
205
|
-
await prismaModel.delete({
|
|
206
|
-
where: { [primaryKey]: typedId }
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Build include object for relations
|
|
213
|
-
*/
|
|
214
|
-
function buildInclude(model) {
|
|
215
|
-
const include = {};
|
|
216
|
-
for (const field of model.fields) {
|
|
217
|
-
if (field.relation && !field.isList) {
|
|
218
|
-
// Only include single relations, not lists (for performance)
|
|
219
|
-
include[field.name] = true;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return Object.keys(include).length > 0 ? include : undefined;
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Process input data for create/update
|
|
226
|
-
*/
|
|
227
|
-
function processInputData(data, model) {
|
|
228
|
-
const processed = {};
|
|
229
|
-
for (const field of model.fields) {
|
|
230
|
-
// Skip auto-generated fields
|
|
231
|
-
if (field.isId || field.isCreatedAt || field.isUpdatedAt)
|
|
232
|
-
continue;
|
|
233
|
-
const value = data[field.name];
|
|
234
|
-
// Skip undefined values
|
|
235
|
-
if (value === undefined)
|
|
236
|
-
continue;
|
|
237
|
-
// Handle relations
|
|
238
|
-
if (field.relation?.fields) {
|
|
239
|
-
// This is the "owning" side of a relation with foreign key
|
|
240
|
-
// User provides the related ID directly
|
|
241
|
-
const fkField = field.relation.fields[0];
|
|
242
|
-
if (data[fkField] !== undefined) {
|
|
243
|
-
processed[fkField] = data[fkField];
|
|
244
|
-
}
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
// Handle type conversions
|
|
248
|
-
if (value !== null && value !== '') {
|
|
249
|
-
switch (field.type) {
|
|
250
|
-
case 'Int':
|
|
251
|
-
case 'BigInt':
|
|
252
|
-
processed[field.name] = parseInt(String(value));
|
|
253
|
-
break;
|
|
254
|
-
case 'Float':
|
|
255
|
-
case 'Decimal':
|
|
256
|
-
processed[field.name] = parseFloat(String(value));
|
|
257
|
-
break;
|
|
258
|
-
case 'Boolean':
|
|
259
|
-
processed[field.name] = value === true || value === 'true' || value === 'on';
|
|
260
|
-
break;
|
|
261
|
-
case 'DateTime':
|
|
262
|
-
processed[field.name] = new Date(String(value));
|
|
263
|
-
break;
|
|
264
|
-
case 'Json':
|
|
265
|
-
processed[field.name] = typeof value === 'string' ? JSON.parse(value) : value;
|
|
266
|
-
break;
|
|
267
|
-
default:
|
|
268
|
-
processed[field.name] = value;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
else if (!field.isRequired) {
|
|
272
|
-
processed[field.name] = null;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return processed;
|
|
276
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './parser.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './parser.js';
|