forge-anvil-app 0.1.0 → 0.2.1
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/bootstrap/actions.ts +362 -0
- package/bootstrap/admin/[slug]/[id]/edit/page.tsx +1 -1
- package/bootstrap/admin/layout.tsx +1 -0
- package/dist/index.js +34 -65
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic CRUD server actions for resources
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
"use server";
|
|
6
|
+
|
|
7
|
+
import { prisma } from "@/lib/prisma";
|
|
8
|
+
import type { AnvilResource } from "./resource";
|
|
9
|
+
|
|
10
|
+
export interface ActionError {
|
|
11
|
+
field?: string;
|
|
12
|
+
message: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ActionResult<T = any> {
|
|
16
|
+
success: boolean;
|
|
17
|
+
data?: T;
|
|
18
|
+
errors?: ActionError[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ResourceRecord {
|
|
22
|
+
id: number | string;
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* List all records for a resource
|
|
28
|
+
*/
|
|
29
|
+
export async function listRecords(
|
|
30
|
+
resource: AnvilResource
|
|
31
|
+
): Promise<ResourceRecord[]> {
|
|
32
|
+
const model = resource.model as keyof typeof prisma;
|
|
33
|
+
const modelClient = (prisma as any)[model];
|
|
34
|
+
|
|
35
|
+
if (!modelClient || typeof modelClient.findMany !== "function") {
|
|
36
|
+
throw new Error(`Model ${resource.model} not found in Prisma client`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const records = await modelClient.findMany({
|
|
40
|
+
orderBy: { id: "desc" },
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return records;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get a single record by ID
|
|
48
|
+
*/
|
|
49
|
+
export async function getRecord(
|
|
50
|
+
resource: AnvilResource,
|
|
51
|
+
id: number | string
|
|
52
|
+
): Promise<ResourceRecord | null> {
|
|
53
|
+
const model = resource.model as keyof typeof prisma;
|
|
54
|
+
const modelClient = (prisma as any)[model];
|
|
55
|
+
|
|
56
|
+
if (!modelClient || typeof modelClient.findUnique !== "function") {
|
|
57
|
+
throw new Error(`Model ${resource.model} not found in Prisma client`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const record = await modelClient.findUnique({
|
|
61
|
+
where: { id: Number(id) },
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return record;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Validate form data against resource definition
|
|
69
|
+
*/
|
|
70
|
+
function validateFormData(
|
|
71
|
+
resource: AnvilResource,
|
|
72
|
+
data: Record<string, any>,
|
|
73
|
+
isUpdate: boolean = false
|
|
74
|
+
): ActionError[] {
|
|
75
|
+
const errors: ActionError[] = [];
|
|
76
|
+
|
|
77
|
+
// Use form for create, editForm for update
|
|
78
|
+
const formFields = isUpdate ? resource.editForm.fields : resource.form.fields;
|
|
79
|
+
|
|
80
|
+
for (const [fieldName, fieldSchema] of Object.entries(formFields)) {
|
|
81
|
+
const value = data[fieldName];
|
|
82
|
+
|
|
83
|
+
// Skip hidden fields
|
|
84
|
+
if (fieldSchema.type === "hidden") {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Skip validation for read-only fields on create
|
|
89
|
+
if ("readOnly" in fieldSchema && fieldSchema.readOnly && !isUpdate) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Required validation
|
|
94
|
+
if (
|
|
95
|
+
"required" in fieldSchema &&
|
|
96
|
+
fieldSchema.required &&
|
|
97
|
+
(value === null || value === undefined || value === "")
|
|
98
|
+
) {
|
|
99
|
+
const label = "label" in fieldSchema ? fieldSchema.label : fieldName;
|
|
100
|
+
errors.push({
|
|
101
|
+
field: fieldName,
|
|
102
|
+
message: `${label} is required`,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Type-specific validation
|
|
107
|
+
if (value !== null && value !== undefined && value !== "") {
|
|
108
|
+
if (fieldSchema.type === "email") {
|
|
109
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
110
|
+
if (!emailRegex.test(value)) {
|
|
111
|
+
errors.push({
|
|
112
|
+
field: fieldName,
|
|
113
|
+
message: `${fieldSchema.label || fieldName} must be a valid email`,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (fieldSchema.type === "text" && "minLength" in fieldSchema) {
|
|
119
|
+
if (fieldSchema.minLength && value.length < fieldSchema.minLength) {
|
|
120
|
+
errors.push({
|
|
121
|
+
field: fieldName,
|
|
122
|
+
message: `${fieldSchema.label || fieldName} must be at least ${
|
|
123
|
+
fieldSchema.minLength
|
|
124
|
+
} characters`,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (fieldSchema.type === "text" && "maxLength" in fieldSchema) {
|
|
130
|
+
if (fieldSchema.maxLength && value.length > fieldSchema.maxLength) {
|
|
131
|
+
errors.push({
|
|
132
|
+
field: fieldName,
|
|
133
|
+
message: `${fieldSchema.label || fieldName} must be no more than ${
|
|
134
|
+
fieldSchema.maxLength
|
|
135
|
+
} characters`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (fieldSchema.type === "number" && "min" in fieldSchema) {
|
|
141
|
+
if (fieldSchema.min !== undefined && Number(value) < fieldSchema.min) {
|
|
142
|
+
errors.push({
|
|
143
|
+
field: fieldName,
|
|
144
|
+
message: `${fieldSchema.label || fieldName} must be at least ${
|
|
145
|
+
fieldSchema.min
|
|
146
|
+
}`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (fieldSchema.type === "number" && "max" in fieldSchema) {
|
|
152
|
+
if (fieldSchema.max !== undefined && Number(value) > fieldSchema.max) {
|
|
153
|
+
errors.push({
|
|
154
|
+
field: fieldName,
|
|
155
|
+
message: `${fieldSchema.label || fieldName} must be no more than ${
|
|
156
|
+
fieldSchema.max
|
|
157
|
+
}`,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return errors;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Transform form data based on field types
|
|
169
|
+
* Converts date strings to Date objects for Prisma
|
|
170
|
+
*/
|
|
171
|
+
function transformFormData(
|
|
172
|
+
resource: AnvilResource,
|
|
173
|
+
data: Record<string, any>,
|
|
174
|
+
isUpdate: boolean = false
|
|
175
|
+
): Record<string, any> {
|
|
176
|
+
const formFields = isUpdate ? resource.editForm.fields : resource.form.fields;
|
|
177
|
+
const transformed: Record<string, any> = {};
|
|
178
|
+
|
|
179
|
+
for (const [fieldName, fieldSchema] of Object.entries(formFields)) {
|
|
180
|
+
if (fieldSchema.type === "hidden") {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (
|
|
184
|
+
!("readOnly" in fieldSchema && fieldSchema.readOnly) &&
|
|
185
|
+
data[fieldName] !== undefined &&
|
|
186
|
+
data[fieldName] !== null &&
|
|
187
|
+
data[fieldName] !== ""
|
|
188
|
+
) {
|
|
189
|
+
// Convert date strings to Date objects
|
|
190
|
+
if (fieldSchema.type === "date") {
|
|
191
|
+
const dateValue = data[fieldName];
|
|
192
|
+
// If it's already a Date object, use it
|
|
193
|
+
if (dateValue instanceof Date) {
|
|
194
|
+
transformed[fieldName] = dateValue;
|
|
195
|
+
} else if (typeof dateValue === "string") {
|
|
196
|
+
// Convert "YYYY-MM-DD" to Date object
|
|
197
|
+
// Add time component to make it a valid DateTime
|
|
198
|
+
const date = new Date(dateValue + "T00:00:00.000Z");
|
|
199
|
+
if (!isNaN(date.getTime())) {
|
|
200
|
+
transformed[fieldName] = date;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
transformed[fieldName] = data[fieldName];
|
|
205
|
+
}
|
|
206
|
+
} else if (data[fieldName] === "" && fieldSchema.type === "date") {
|
|
207
|
+
// Handle empty date strings - set to null
|
|
208
|
+
transformed[fieldName] = null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return transformed;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Create a new record
|
|
217
|
+
*/
|
|
218
|
+
export async function createRecord(
|
|
219
|
+
resource: AnvilResource,
|
|
220
|
+
data: Record<string, any>
|
|
221
|
+
): Promise<ActionResult<any>> {
|
|
222
|
+
// Validate
|
|
223
|
+
const errors = validateFormData(resource, data, false);
|
|
224
|
+
if (errors.length > 0) {
|
|
225
|
+
return { success: false, errors };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Check unique constraints
|
|
229
|
+
for (const [fieldName, fieldSchema] of Object.entries(resource.form.fields)) {
|
|
230
|
+
if (fieldSchema.type === "email" || fieldSchema.type === "text") {
|
|
231
|
+
if (fieldSchema.unique && data[fieldName]) {
|
|
232
|
+
const model = resource.model as keyof typeof prisma;
|
|
233
|
+
const modelClient = (prisma as any)[model];
|
|
234
|
+
|
|
235
|
+
const existing = await modelClient.findFirst({
|
|
236
|
+
where: { [fieldName]: data[fieldName] },
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
if (existing) {
|
|
240
|
+
return {
|
|
241
|
+
success: false,
|
|
242
|
+
errors: [
|
|
243
|
+
{
|
|
244
|
+
field: fieldName,
|
|
245
|
+
message: `${fieldSchema.label || fieldName} must be unique`,
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Transform and prepare data (exclude read-only and hidden fields)
|
|
255
|
+
const transformedData = transformFormData(resource, data, false);
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
const model = resource.model as keyof typeof prisma;
|
|
259
|
+
const modelClient = (prisma as any)[model];
|
|
260
|
+
|
|
261
|
+
const record = await modelClient.create({
|
|
262
|
+
data: transformedData,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
return { success: true, data: record };
|
|
266
|
+
} catch (error: any) {
|
|
267
|
+
return {
|
|
268
|
+
success: false,
|
|
269
|
+
errors: [{ message: error.message || "Failed to create record" }],
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Update an existing record
|
|
276
|
+
*/
|
|
277
|
+
export async function updateRecord(
|
|
278
|
+
resource: AnvilResource,
|
|
279
|
+
id: number | string,
|
|
280
|
+
data: Record<string, any>
|
|
281
|
+
): Promise<ActionResult<ResourceRecord>> {
|
|
282
|
+
// Validate
|
|
283
|
+
const errors = validateFormData(resource, data, true);
|
|
284
|
+
if (errors.length > 0) {
|
|
285
|
+
return { success: false, errors };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Check unique constraints (excluding current record)
|
|
289
|
+
for (const [fieldName, fieldSchema] of Object.entries(
|
|
290
|
+
resource.editForm.fields
|
|
291
|
+
)) {
|
|
292
|
+
if (fieldSchema.type === "email" || fieldSchema.type === "text") {
|
|
293
|
+
if (fieldSchema.unique && data[fieldName]) {
|
|
294
|
+
const model = resource.model as keyof typeof prisma;
|
|
295
|
+
const modelClient = (prisma as any)[model];
|
|
296
|
+
|
|
297
|
+
const existing = await modelClient.findFirst({
|
|
298
|
+
where: {
|
|
299
|
+
[fieldName]: data[fieldName],
|
|
300
|
+
NOT: { id: Number(id) },
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (existing) {
|
|
305
|
+
return {
|
|
306
|
+
success: false,
|
|
307
|
+
errors: [
|
|
308
|
+
{
|
|
309
|
+
field: fieldName,
|
|
310
|
+
message: `${fieldSchema.label || fieldName} must be unique`,
|
|
311
|
+
},
|
|
312
|
+
],
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Transform and prepare data (exclude read-only and hidden fields on update)
|
|
320
|
+
const transformedData = transformFormData(resource, data, true);
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
const model = resource.model as keyof typeof prisma;
|
|
324
|
+
const modelClient = (prisma as any)[model];
|
|
325
|
+
|
|
326
|
+
const record = await modelClient.update({
|
|
327
|
+
where: { id: Number(id) },
|
|
328
|
+
data: transformedData,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
return { success: true, data: record };
|
|
332
|
+
} catch (error: any) {
|
|
333
|
+
return {
|
|
334
|
+
success: false,
|
|
335
|
+
errors: [{ message: error.message || "Failed to update record" }],
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Delete a record
|
|
342
|
+
*/
|
|
343
|
+
export async function deleteRecord(
|
|
344
|
+
resource: AnvilResource,
|
|
345
|
+
id: number | string
|
|
346
|
+
): Promise<ActionResult> {
|
|
347
|
+
try {
|
|
348
|
+
const model = resource.model as keyof typeof prisma;
|
|
349
|
+
const modelClient = (prisma as any)[model];
|
|
350
|
+
|
|
351
|
+
await modelClient.delete({
|
|
352
|
+
where: { id: Number(id) },
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
return { success: true };
|
|
356
|
+
} catch (error: any) {
|
|
357
|
+
return {
|
|
358
|
+
success: false,
|
|
359
|
+
errors: [{ message: error.message || "Failed to delete record" }],
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Server Component - handles data fetching and server actions
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { EditResourceForm } from "@/components/
|
|
6
|
+
import { EditResourceForm } from "@/components/anvil/EditResourceForm";
|
|
7
7
|
import { updateRecord, getRecord } from "@/lib/anvil/actions";
|
|
8
8
|
import { AnvilResource } from "@/lib/anvil/resource";
|
|
9
9
|
import { redirect } from "next/navigation";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execSync } from "child_process";
|
|
3
|
-
import { existsSync, mkdirSync,
|
|
3
|
+
import { existsSync, mkdirSync, cpSync } from "fs";
|
|
4
4
|
import { join, dirname } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -45,10 +45,10 @@ console.log("\n📋 Copying Anvil bootstrap files...");
|
|
|
45
45
|
const bootstrapDir = join(__dirname, "..", "bootstrap");
|
|
46
46
|
// Copy admin folder to app/admin
|
|
47
47
|
const bootstrapAdminDir = join(bootstrapDir, "admin");
|
|
48
|
-
const targetAdminDir = join(projectPath, "app", "admin");
|
|
48
|
+
const targetAdminDir = join(projectPath, "src", "app", "admin");
|
|
49
49
|
if (existsSync(bootstrapAdminDir)) {
|
|
50
50
|
cpSync(bootstrapAdminDir, targetAdminDir, { recursive: true });
|
|
51
|
-
console.log(" ✅ Copied admin folder to app/admin");
|
|
51
|
+
console.log(" ✅ Copied admin folder to src/app/admin");
|
|
52
52
|
}
|
|
53
53
|
// Copy components folder to src/components
|
|
54
54
|
const bootstrapComponentsDir = join(bootstrapDir, "components");
|
|
@@ -58,73 +58,42 @@ if (existsSync(bootstrapComponentsDir)) {
|
|
|
58
58
|
cpSync(bootstrapComponentsDir, targetComponentsDir, { recursive: true });
|
|
59
59
|
console.log(" ✅ Copied components folder to src/components");
|
|
60
60
|
}
|
|
61
|
+
// Copy actions.ts to anvil/actions.ts
|
|
62
|
+
const bootstrapActionsPath = join(bootstrapDir, "actions.ts");
|
|
63
|
+
const targetActionsDir = join(projectPath, "src", "lib", "anvil");
|
|
64
|
+
if (existsSync(bootstrapActionsPath)) {
|
|
65
|
+
mkdirSync(targetActionsDir, { recursive: true });
|
|
66
|
+
cpSync(bootstrapActionsPath, join(targetActionsDir, "actions.ts"));
|
|
67
|
+
console.log(" ✅ Copied actions.ts to src/lib/anvil/actions.ts");
|
|
68
|
+
}
|
|
61
69
|
// Step 3: Add Anvil-specific files and configuration
|
|
62
70
|
console.log("\n🔨 Setting up Anvil configuration...");
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
packageJson.scripts.anvil = "anvil";
|
|
75
|
-
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
76
|
-
// Create app layout with Anvil styles import
|
|
77
|
-
const appLayoutPath = join(projectPath, "app", "layout.tsx");
|
|
78
|
-
if (existsSync(appLayoutPath)) {
|
|
79
|
-
let layoutContent = readFileSync(appLayoutPath, "utf-8");
|
|
80
|
-
// Add Anvil styles import if not already present
|
|
81
|
-
if (!layoutContent.includes("next-anvil/styles.css")) {
|
|
82
|
-
// Find the last import statement
|
|
83
|
-
const lastImportIndex = layoutContent.lastIndexOf("import");
|
|
84
|
-
const nextLineAfterLastImport = layoutContent.indexOf("\n", lastImportIndex) + 1;
|
|
85
|
-
layoutContent =
|
|
86
|
-
layoutContent.slice(0, nextLineAfterLastImport) +
|
|
87
|
-
'import "next-anvil/styles.css";\n' +
|
|
88
|
-
layoutContent.slice(nextLineAfterLastImport);
|
|
89
|
-
writeFileSync(appLayoutPath, layoutContent);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
// Create example .env.local with Prisma DATABASE_URL
|
|
93
|
-
const envLocalPath = join(projectPath, ".env.local");
|
|
94
|
-
if (!existsSync(envLocalPath)) {
|
|
95
|
-
writeFileSync(envLocalPath, `# Database
|
|
96
|
-
DATABASE_URL="postgresql://user:password@localhost:5432/anvil?schema=public"
|
|
97
|
-
|
|
98
|
-
# Next.js
|
|
99
|
-
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
100
|
-
`);
|
|
101
|
-
}
|
|
102
|
-
// Create example prisma schema
|
|
103
|
-
const prismaDir = join(projectPath, "prisma");
|
|
104
|
-
mkdirSync(prismaDir, { recursive: true });
|
|
105
|
-
const prismaSchemaPath = join(prismaDir, "schema.prisma");
|
|
106
|
-
if (!existsSync(prismaSchemaPath)) {
|
|
107
|
-
writeFileSync(prismaSchemaPath, `// This is your Prisma schema file,
|
|
108
|
-
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
109
|
-
|
|
110
|
-
generator client {
|
|
111
|
-
provider = "prisma-client-js"
|
|
71
|
+
// Step 4: Install Prisma and dependencies
|
|
72
|
+
console.log("\n📦 Installing Prisma and database dependencies...");
|
|
73
|
+
try {
|
|
74
|
+
execSync("npm install prisma @types/node @types/pg --save-dev", {
|
|
75
|
+
stdio: "inherit",
|
|
76
|
+
cwd: projectPath,
|
|
77
|
+
});
|
|
78
|
+
execSync("npm install @prisma/client @prisma/adapter-pg pg dotenv", {
|
|
79
|
+
stdio: "inherit",
|
|
80
|
+
cwd: projectPath,
|
|
81
|
+
});
|
|
112
82
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
url = env("DATABASE_URL")
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error("Failed to install Prisma:", error);
|
|
85
|
+
process.exit(1);
|
|
117
86
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
updatedAt DateTime @updatedAt
|
|
87
|
+
// Step 5: Initialize Prisma client
|
|
88
|
+
console.log("\n🔧 Initializing Prisma client...");
|
|
89
|
+
try {
|
|
90
|
+
execSync("npx prisma init", {
|
|
91
|
+
stdio: "inherit",
|
|
92
|
+
cwd: projectPath,
|
|
93
|
+
});
|
|
126
94
|
}
|
|
127
|
-
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.warn("⚠️ Prisma initialization failed.");
|
|
128
97
|
}
|
|
129
98
|
console.log("\n✅ Anvil setup complete!");
|
|
130
99
|
console.log("\n📝 Next steps:");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|