archetype-engine 2.0.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/LICENSE +21 -0
- package/README.md +241 -0
- package/dist/src/ai/adapters/anthropic.d.ts +31 -0
- package/dist/src/ai/adapters/anthropic.d.ts.map +1 -0
- package/dist/src/ai/adapters/anthropic.js +75 -0
- package/dist/src/ai/adapters/openai.d.ts +33 -0
- package/dist/src/ai/adapters/openai.d.ts.map +1 -0
- package/dist/src/ai/adapters/openai.js +120 -0
- package/dist/src/ai/adapters/vercel.d.ts +434 -0
- package/dist/src/ai/adapters/vercel.d.ts.map +1 -0
- package/dist/src/ai/adapters/vercel.js +162 -0
- package/dist/src/ai/index.d.ts +492 -0
- package/dist/src/ai/index.d.ts.map +1 -0
- package/dist/src/ai/index.js +71 -0
- package/dist/src/ai/state.d.ts +13 -0
- package/dist/src/ai/state.d.ts.map +1 -0
- package/dist/src/ai/state.js +215 -0
- package/dist/src/ai/tools.d.ts +13 -0
- package/dist/src/ai/tools.d.ts.map +1 -0
- package/dist/src/ai/tools.js +257 -0
- package/dist/src/ai/types.d.ts +196 -0
- package/dist/src/ai/types.d.ts.map +1 -0
- package/dist/src/ai/types.js +9 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +540 -0
- package/dist/src/core/utils.d.ts +27 -0
- package/dist/src/core/utils.d.ts.map +1 -0
- package/dist/src/core/utils.js +56 -0
- package/dist/src/entity.d.ts +165 -0
- package/dist/src/entity.d.ts.map +1 -0
- package/dist/src/entity.js +108 -0
- package/dist/src/fields.d.ts +207 -0
- package/dist/src/fields.d.ts.map +1 -0
- package/dist/src/fields.js +291 -0
- package/dist/src/generators/erd-ir.d.ts +10 -0
- package/dist/src/generators/erd-ir.d.ts.map +1 -0
- package/dist/src/generators/erd-ir.js +119 -0
- package/dist/src/index.d.ts +51 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +101 -0
- package/dist/src/init/dependencies.d.ts +31 -0
- package/dist/src/init/dependencies.d.ts.map +1 -0
- package/dist/src/init/dependencies.js +101 -0
- package/dist/src/init/entity-templates.d.ts +42 -0
- package/dist/src/init/entity-templates.d.ts.map +1 -0
- package/dist/src/init/entity-templates.js +367 -0
- package/dist/src/init/index.d.ts +10 -0
- package/dist/src/init/index.d.ts.map +1 -0
- package/dist/src/init/index.js +250 -0
- package/dist/src/init/prompts.d.ts +11 -0
- package/dist/src/init/prompts.d.ts.map +1 -0
- package/dist/src/init/prompts.js +275 -0
- package/dist/src/init/templates.d.ts +24 -0
- package/dist/src/init/templates.d.ts.map +1 -0
- package/dist/src/init/templates.js +587 -0
- package/dist/src/json/index.d.ts +11 -0
- package/dist/src/json/index.d.ts.map +1 -0
- package/dist/src/json/index.js +26 -0
- package/dist/src/json/parser.d.ts +61 -0
- package/dist/src/json/parser.d.ts.map +1 -0
- package/dist/src/json/parser.js +309 -0
- package/dist/src/json/types.d.ts +275 -0
- package/dist/src/json/types.d.ts.map +1 -0
- package/dist/src/json/types.js +10 -0
- package/dist/src/manifest.d.ts +147 -0
- package/dist/src/manifest.d.ts.map +1 -0
- package/dist/src/manifest.js +104 -0
- package/dist/src/relations.d.ts +96 -0
- package/dist/src/relations.d.ts.map +1 -0
- package/dist/src/relations.js +108 -0
- package/dist/src/source.d.ts +93 -0
- package/dist/src/source.d.ts.map +1 -0
- package/dist/src/source.js +89 -0
- package/dist/src/template/context.d.ts +34 -0
- package/dist/src/template/context.d.ts.map +1 -0
- package/dist/src/template/context.js +31 -0
- package/dist/src/template/index.d.ts +6 -0
- package/dist/src/template/index.d.ts.map +1 -0
- package/dist/src/template/index.js +12 -0
- package/dist/src/template/registry.d.ts +18 -0
- package/dist/src/template/registry.d.ts.map +1 -0
- package/dist/src/template/registry.js +89 -0
- package/dist/src/template/runner.d.ts +9 -0
- package/dist/src/template/runner.d.ts.map +1 -0
- package/dist/src/template/runner.js +125 -0
- package/dist/src/template/types.d.ts +73 -0
- package/dist/src/template/types.d.ts.map +1 -0
- package/dist/src/template/types.js +3 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/api.d.ts +22 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/api.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/api.js +866 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.d.ts +20 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.js +273 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.d.ts +22 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.js +237 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.d.ts +30 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.js +345 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.d.ts +25 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.js +199 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/index.d.ts +8 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/index.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/index.js +18 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.d.ts +22 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.js +270 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/service.d.ts +23 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/service.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/service.js +304 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.d.ts +21 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.js +248 -0
- package/dist/src/templates/nextjs-drizzle-trpc/index.d.ts +30 -0
- package/dist/src/templates/nextjs-drizzle-trpc/index.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/index.js +71 -0
- package/dist/src/validation/index.d.ts +71 -0
- package/dist/src/validation/index.d.ts.map +1 -0
- package/dist/src/validation/index.js +314 -0
- package/package.json +86 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Validation Module for AI Agent Input
|
|
4
|
+
*
|
|
5
|
+
* Provides structured validation with error codes that AI agents can parse
|
|
6
|
+
* and use to fix their output.
|
|
7
|
+
*
|
|
8
|
+
* @module validation
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.ValidationCodes = void 0;
|
|
12
|
+
exports.validateManifest = validateManifest;
|
|
13
|
+
// Error codes
|
|
14
|
+
exports.ValidationCodes = {
|
|
15
|
+
// Entity errors
|
|
16
|
+
INVALID_ENTITY_NAME: 'INVALID_ENTITY_NAME',
|
|
17
|
+
DUPLICATE_ENTITY: 'DUPLICATE_ENTITY',
|
|
18
|
+
MISSING_ENTITY_FIELDS: 'MISSING_ENTITY_FIELDS',
|
|
19
|
+
// Field errors
|
|
20
|
+
INVALID_FIELD_TYPE: 'INVALID_FIELD_TYPE',
|
|
21
|
+
INVALID_FIELD_NAME: 'INVALID_FIELD_NAME',
|
|
22
|
+
// Relation errors
|
|
23
|
+
RELATION_TARGET_NOT_FOUND: 'RELATION_TARGET_NOT_FOUND',
|
|
24
|
+
INVALID_RELATION_TYPE: 'INVALID_RELATION_TYPE',
|
|
25
|
+
// Database errors
|
|
26
|
+
DATABASE_REQUIRED: 'DATABASE_REQUIRED',
|
|
27
|
+
INVALID_DATABASE_TYPE: 'INVALID_DATABASE_TYPE',
|
|
28
|
+
SQLITE_REQUIRES_FILE: 'SQLITE_REQUIRES_FILE',
|
|
29
|
+
POSTGRES_REQUIRES_URL: 'POSTGRES_REQUIRES_URL',
|
|
30
|
+
// Auth errors
|
|
31
|
+
AUTH_REQUIRED_FOR_PROTECTED: 'AUTH_REQUIRED_FOR_PROTECTED',
|
|
32
|
+
INVALID_PROVIDER: 'INVALID_PROVIDER',
|
|
33
|
+
// Mode errors
|
|
34
|
+
INVALID_MODE: 'INVALID_MODE',
|
|
35
|
+
// Protected errors
|
|
36
|
+
INVALID_PROTECTED_VALUE: 'INVALID_PROTECTED_VALUE',
|
|
37
|
+
// Source errors
|
|
38
|
+
EXTERNAL_SOURCE_INVALID: 'EXTERNAL_SOURCE_INVALID',
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Check if a string is PascalCase
|
|
42
|
+
*/
|
|
43
|
+
function isPascalCase(str) {
|
|
44
|
+
return /^[A-Z][a-zA-Z0-9]*$/.test(str);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if a string is camelCase
|
|
48
|
+
*/
|
|
49
|
+
function isCamelCase(str) {
|
|
50
|
+
return /^[a-z][a-zA-Z0-9]*$/.test(str);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Validate a field definition
|
|
54
|
+
*/
|
|
55
|
+
function validateField(fieldName, field, entityName) {
|
|
56
|
+
const errors = [];
|
|
57
|
+
const path = `${entityName}.fields.${fieldName}`;
|
|
58
|
+
// Check field name is camelCase
|
|
59
|
+
if (!isCamelCase(fieldName)) {
|
|
60
|
+
errors.push({
|
|
61
|
+
code: exports.ValidationCodes.INVALID_FIELD_NAME,
|
|
62
|
+
path,
|
|
63
|
+
message: `Field name '${fieldName}' must be camelCase`,
|
|
64
|
+
suggestion: `Rename to '${fieldName.charAt(0).toLowerCase()}${fieldName.slice(1)}'`,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// Check field type is valid
|
|
68
|
+
const validTypes = ['text', 'number', 'boolean', 'date'];
|
|
69
|
+
if (!validTypes.includes(field.type)) {
|
|
70
|
+
errors.push({
|
|
71
|
+
code: exports.ValidationCodes.INVALID_FIELD_TYPE,
|
|
72
|
+
path: `${path}.type`,
|
|
73
|
+
message: `Invalid field type '${field.type}'`,
|
|
74
|
+
suggestion: `Use one of: ${validTypes.join(', ')}`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return errors;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Validate a relation definition
|
|
81
|
+
*/
|
|
82
|
+
function validateRelation(relationName, relation, entityName, entityNames) {
|
|
83
|
+
const errors = [];
|
|
84
|
+
const path = `${entityName}.relations.${relationName}`;
|
|
85
|
+
// Check relation type is valid
|
|
86
|
+
const validTypes = ['hasOne', 'hasMany', 'belongsToMany'];
|
|
87
|
+
if (!validTypes.includes(relation.type)) {
|
|
88
|
+
errors.push({
|
|
89
|
+
code: exports.ValidationCodes.INVALID_RELATION_TYPE,
|
|
90
|
+
path: `${path}.type`,
|
|
91
|
+
message: `Invalid relation type '${relation.type}'`,
|
|
92
|
+
suggestion: `Use one of: ${validTypes.join(', ')}`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Check target entity exists
|
|
96
|
+
if (!entityNames.has(relation.entity)) {
|
|
97
|
+
errors.push({
|
|
98
|
+
code: exports.ValidationCodes.RELATION_TARGET_NOT_FOUND,
|
|
99
|
+
path: `${path}.entity`,
|
|
100
|
+
message: `Entity '${relation.entity}' not found in manifest`,
|
|
101
|
+
suggestion: `Add entity '${relation.entity}' to the entities array, or fix the entity name`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return errors;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Validate an entity definition
|
|
108
|
+
*/
|
|
109
|
+
function validateEntity(entity, entityNames, authEnabled) {
|
|
110
|
+
const errors = [];
|
|
111
|
+
const path = entity.name;
|
|
112
|
+
// Check entity name is PascalCase
|
|
113
|
+
if (!isPascalCase(entity.name)) {
|
|
114
|
+
errors.push({
|
|
115
|
+
code: exports.ValidationCodes.INVALID_ENTITY_NAME,
|
|
116
|
+
path,
|
|
117
|
+
message: `Entity name '${entity.name}' must be PascalCase`,
|
|
118
|
+
suggestion: `Rename to '${entity.name.charAt(0).toUpperCase()}${entity.name.slice(1)}'`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// Check entity has fields
|
|
122
|
+
if (!entity.fields || Object.keys(entity.fields).length === 0) {
|
|
123
|
+
errors.push({
|
|
124
|
+
code: exports.ValidationCodes.MISSING_ENTITY_FIELDS,
|
|
125
|
+
path: `${path}.fields`,
|
|
126
|
+
message: `Entity '${entity.name}' must have at least one field`,
|
|
127
|
+
suggestion: `Add fields to the entity`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// Validate fields
|
|
131
|
+
if (entity.fields) {
|
|
132
|
+
for (const [fieldName, field] of Object.entries(entity.fields)) {
|
|
133
|
+
errors.push(...validateField(fieldName, field, entity.name));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Validate relations
|
|
137
|
+
if (entity.relations) {
|
|
138
|
+
for (const [relationName, relation] of Object.entries(entity.relations)) {
|
|
139
|
+
errors.push(...validateRelation(relationName, relation, entity.name, entityNames));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Check protected requires auth
|
|
143
|
+
if (entity.protected !== undefined && entity.protected !== false) {
|
|
144
|
+
if (!authEnabled) {
|
|
145
|
+
errors.push({
|
|
146
|
+
code: exports.ValidationCodes.AUTH_REQUIRED_FOR_PROTECTED,
|
|
147
|
+
path: `${path}.protected`,
|
|
148
|
+
message: `Entity '${entity.name}' has protected operations but auth is not enabled`,
|
|
149
|
+
suggestion: `Add auth: { enabled: true } to manifest, or remove protected from entity`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// Validate protected value
|
|
153
|
+
const validProtectedStrings = ['write', 'all'];
|
|
154
|
+
if (typeof entity.protected !== 'boolean' &&
|
|
155
|
+
typeof entity.protected !== 'object' &&
|
|
156
|
+
!validProtectedStrings.includes(entity.protected)) {
|
|
157
|
+
errors.push({
|
|
158
|
+
code: exports.ValidationCodes.INVALID_PROTECTED_VALUE,
|
|
159
|
+
path: `${path}.protected`,
|
|
160
|
+
message: `Invalid protected value '${entity.protected}'`,
|
|
161
|
+
suggestion: `Use one of: true, false, 'write', 'all', or an object with list/get/create/update/remove`,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Validate external source
|
|
166
|
+
if (entity.source && !entity.source.baseUrl) {
|
|
167
|
+
errors.push({
|
|
168
|
+
code: exports.ValidationCodes.EXTERNAL_SOURCE_INVALID,
|
|
169
|
+
path: `${path}.source.baseUrl`,
|
|
170
|
+
message: `External source requires baseUrl`,
|
|
171
|
+
suggestion: `Add baseUrl to source, e.g., 'env:API_URL' or 'https://api.example.com'`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return errors;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Validate database configuration
|
|
178
|
+
*/
|
|
179
|
+
function validateDatabase(manifest) {
|
|
180
|
+
const errors = [];
|
|
181
|
+
const mode = manifest.mode || 'full';
|
|
182
|
+
// Full mode requires database
|
|
183
|
+
if (mode === 'full' && !manifest.database) {
|
|
184
|
+
errors.push({
|
|
185
|
+
code: exports.ValidationCodes.DATABASE_REQUIRED,
|
|
186
|
+
path: 'database',
|
|
187
|
+
message: `Mode 'full' requires database configuration`,
|
|
188
|
+
suggestion: `Add database config or use mode: 'headless'`,
|
|
189
|
+
});
|
|
190
|
+
return errors;
|
|
191
|
+
}
|
|
192
|
+
if (manifest.database) {
|
|
193
|
+
const db = manifest.database;
|
|
194
|
+
// Check database type
|
|
195
|
+
const validTypes = ['sqlite', 'postgres', 'mysql'];
|
|
196
|
+
if (!validTypes.includes(db.type)) {
|
|
197
|
+
errors.push({
|
|
198
|
+
code: exports.ValidationCodes.INVALID_DATABASE_TYPE,
|
|
199
|
+
path: 'database.type',
|
|
200
|
+
message: `Invalid database type '${db.type}'`,
|
|
201
|
+
suggestion: `Use one of: ${validTypes.join(', ')}`,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// SQLite requires file
|
|
205
|
+
if (db.type === 'sqlite' && !db.file) {
|
|
206
|
+
errors.push({
|
|
207
|
+
code: exports.ValidationCodes.SQLITE_REQUIRES_FILE,
|
|
208
|
+
path: 'database.file',
|
|
209
|
+
message: `SQLite database requires file path`,
|
|
210
|
+
suggestion: `Add file: './sqlite.db' to database config`,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
// Postgres/MySQL requires url
|
|
214
|
+
if ((db.type === 'postgres' || db.type === 'mysql') && !db.url) {
|
|
215
|
+
errors.push({
|
|
216
|
+
code: exports.ValidationCodes.POSTGRES_REQUIRES_URL,
|
|
217
|
+
path: 'database.url',
|
|
218
|
+
message: `${db.type} database requires connection URL`,
|
|
219
|
+
suggestion: `Add url: 'env:DATABASE_URL' or a connection string`,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return errors;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Validate auth configuration
|
|
227
|
+
*/
|
|
228
|
+
function validateAuth(manifest) {
|
|
229
|
+
const errors = [];
|
|
230
|
+
if (manifest.auth?.providers) {
|
|
231
|
+
const validProviders = ['credentials', 'google', 'github', 'discord'];
|
|
232
|
+
for (const provider of manifest.auth.providers) {
|
|
233
|
+
if (!validProviders.includes(provider)) {
|
|
234
|
+
errors.push({
|
|
235
|
+
code: exports.ValidationCodes.INVALID_PROVIDER,
|
|
236
|
+
path: 'auth.providers',
|
|
237
|
+
message: `Invalid auth provider '${provider}'`,
|
|
238
|
+
suggestion: `Use one of: ${validProviders.join(', ')}`,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return errors;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Validate a JSON manifest
|
|
247
|
+
*
|
|
248
|
+
* @param manifest - JSON manifest to validate
|
|
249
|
+
* @returns Validation result with errors and warnings
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* const result = validateManifest({
|
|
254
|
+
* entities: [{ name: 'User', fields: { email: { type: 'text' } } }],
|
|
255
|
+
* database: { type: 'sqlite', file: './app.db' }
|
|
256
|
+
* })
|
|
257
|
+
*
|
|
258
|
+
* if (!result.valid) {
|
|
259
|
+
* console.log('Errors:', result.errors)
|
|
260
|
+
* }
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
function validateManifest(manifest) {
|
|
264
|
+
const errors = [];
|
|
265
|
+
const warnings = [];
|
|
266
|
+
// Validate mode
|
|
267
|
+
const validModes = ['full', 'headless', 'api-only'];
|
|
268
|
+
if (manifest.mode && !validModes.includes(manifest.mode)) {
|
|
269
|
+
errors.push({
|
|
270
|
+
code: exports.ValidationCodes.INVALID_MODE,
|
|
271
|
+
path: 'mode',
|
|
272
|
+
message: `Invalid mode '${manifest.mode}'`,
|
|
273
|
+
suggestion: `Use one of: ${validModes.join(', ')}`,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
// Validate database
|
|
277
|
+
errors.push(...validateDatabase(manifest));
|
|
278
|
+
// Validate auth
|
|
279
|
+
errors.push(...validateAuth(manifest));
|
|
280
|
+
// Collect entity names for relation validation
|
|
281
|
+
const entityNames = new Set(manifest.entities.map(e => e.name));
|
|
282
|
+
// Check for duplicate entity names
|
|
283
|
+
const seenNames = new Set();
|
|
284
|
+
for (const entity of manifest.entities) {
|
|
285
|
+
if (seenNames.has(entity.name)) {
|
|
286
|
+
errors.push({
|
|
287
|
+
code: exports.ValidationCodes.DUPLICATE_ENTITY,
|
|
288
|
+
path: entity.name,
|
|
289
|
+
message: `Duplicate entity name '${entity.name}'`,
|
|
290
|
+
suggestion: `Rename one of the entities`,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
seenNames.add(entity.name);
|
|
294
|
+
}
|
|
295
|
+
// Validate each entity
|
|
296
|
+
const authEnabled = manifest.auth?.enabled || false;
|
|
297
|
+
for (const entity of manifest.entities) {
|
|
298
|
+
errors.push(...validateEntity(entity, entityNames, authEnabled));
|
|
299
|
+
}
|
|
300
|
+
// Validate global source
|
|
301
|
+
if (manifest.source && !manifest.source.baseUrl) {
|
|
302
|
+
errors.push({
|
|
303
|
+
code: exports.ValidationCodes.EXTERNAL_SOURCE_INVALID,
|
|
304
|
+
path: 'source.baseUrl',
|
|
305
|
+
message: `Global external source requires baseUrl`,
|
|
306
|
+
suggestion: `Add baseUrl to source, e.g., 'env:API_URL'`,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
valid: errors.length === 0,
|
|
311
|
+
errors,
|
|
312
|
+
warnings,
|
|
313
|
+
};
|
|
314
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "archetype-engine",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Type-safe backend generator for Next.js. Define entities once, get Drizzle schemas, tRPC APIs, Zod validation, and React hooks instantly.",
|
|
5
|
+
"main": "dist/src/index.js",
|
|
6
|
+
"types": "dist/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/src/index.d.ts",
|
|
10
|
+
"import": "./dist/src/index.js",
|
|
11
|
+
"require": "./dist/src/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./ai": {
|
|
14
|
+
"types": "./dist/src/ai/index.d.ts",
|
|
15
|
+
"import": "./dist/src/ai/index.js",
|
|
16
|
+
"require": "./dist/src/ai/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"bin": {
|
|
20
|
+
"archetype": "dist/src/cli.js"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20.0.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"prepublishOnly": "npm run build",
|
|
32
|
+
"test": "vitest",
|
|
33
|
+
"test:run": "vitest run",
|
|
34
|
+
"init": "node dist/src/cli.js init",
|
|
35
|
+
"generate": "node dist/src/cli.js generate"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@clack/prompts": "^0.11.0",
|
|
39
|
+
"puppeteer": "^24.34.0",
|
|
40
|
+
"ts-node": "^10.9.2",
|
|
41
|
+
"zod": "^3.23.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.5.5",
|
|
45
|
+
"typedoc": "^0.28.15",
|
|
46
|
+
"typescript": "^5.9.3",
|
|
47
|
+
"vitest": "^4.0.16"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"typescript": ">=5.0.0"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"nextjs",
|
|
54
|
+
"backend-generator",
|
|
55
|
+
"code-generation",
|
|
56
|
+
"drizzle",
|
|
57
|
+
"trpc",
|
|
58
|
+
"zod",
|
|
59
|
+
"react-query",
|
|
60
|
+
"type-safe",
|
|
61
|
+
"crud",
|
|
62
|
+
"api-generator",
|
|
63
|
+
"typescript",
|
|
64
|
+
"fullstack",
|
|
65
|
+
"scaffolding",
|
|
66
|
+
"boilerplate",
|
|
67
|
+
"v0",
|
|
68
|
+
"cursor",
|
|
69
|
+
"ai-backend",
|
|
70
|
+
"prisma-alternative",
|
|
71
|
+
"orm",
|
|
72
|
+
"schema-first",
|
|
73
|
+
"declarative",
|
|
74
|
+
"entity-framework"
|
|
75
|
+
],
|
|
76
|
+
"author": "IFAKA",
|
|
77
|
+
"license": "MIT",
|
|
78
|
+
"repository": {
|
|
79
|
+
"type": "git",
|
|
80
|
+
"url": "git+https://github.com/IFAKA/archetype-engine.git"
|
|
81
|
+
},
|
|
82
|
+
"bugs": {
|
|
83
|
+
"url": "https://github.com/IFAKA/archetype-engine/issues"
|
|
84
|
+
},
|
|
85
|
+
"homepage": "https://archetype-engine.vercel.app"
|
|
86
|
+
}
|