archetype-engine 2.2.0 → 2.3.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/README.md +66 -0
- package/dist/src/cli.js +90 -1
- package/dist/src/entity.d.ts +2 -0
- package/dist/src/entity.d.ts.map +1 -1
- package/dist/src/entity.js +1 -0
- package/dist/src/init/dependencies.d.ts.map +1 -1
- package/dist/src/init/dependencies.js +2 -0
- package/dist/src/init/templates.d.ts +1 -0
- package/dist/src/init/templates.d.ts.map +1 -1
- package/dist/src/init/templates.js +52 -15
- package/dist/src/json/parser.d.ts.map +1 -1
- package/dist/src/json/parser.js +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/seed.d.ts.map +1 -1
- package/dist/src/templates/nextjs-drizzle-trpc/generators/seed.js +6 -4
- package/dist/src/templates/nextjs-drizzle-trpc/generators/test.d.ts.map +1 -1
- package/dist/src/templates/nextjs-drizzle-trpc/generators/test.js +14 -13
- package/dist/src/validation/index.d.ts.map +1 -1
- package/dist/src/validation/index.js +11 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -214,6 +214,72 @@ Archetype generates the **missing backend layer**:
|
|
|
214
214
|
|
|
215
215
|
---
|
|
216
216
|
|
|
217
|
+
## CLI Commands
|
|
218
|
+
|
|
219
|
+
Archetype provides a suite of commands organized by namespace to avoid conflicts with your Next.js project:
|
|
220
|
+
|
|
221
|
+
### Archetype Commands (Code Generation & Documentation)
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
npx archetype init # Interactive setup with entity templates
|
|
225
|
+
npx archetype generate # Generate all code from entities
|
|
226
|
+
npx archetype view # View ERD diagram in browser (port 3333)
|
|
227
|
+
npx archetype docs # View OpenAPI/Swagger UI (port 3334)
|
|
228
|
+
npx archetype validate # Validate manifest without generating
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Project Scripts (Added by `npx archetype init`)
|
|
232
|
+
|
|
233
|
+
New projects automatically get these npm scripts:
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
{
|
|
237
|
+
"scripts": {
|
|
238
|
+
// Archetype - Generation & Docs
|
|
239
|
+
"archetype:generate": "archetype generate",
|
|
240
|
+
"archetype:view": "archetype view",
|
|
241
|
+
"archetype:docs": "archetype docs",
|
|
242
|
+
"archetype:check": "archetype validate",
|
|
243
|
+
|
|
244
|
+
// Database - Schema & Data
|
|
245
|
+
"db:push": "drizzle-kit push",
|
|
246
|
+
"db:studio": "drizzle-kit studio",
|
|
247
|
+
"db:seed": "tsx generated/seeds/run.ts",
|
|
248
|
+
"db:seed:reset": "tsx generated/seeds/run.ts --reset",
|
|
249
|
+
|
|
250
|
+
// Testing
|
|
251
|
+
"test:api": "vitest run generated/tests"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Common Workflows
|
|
257
|
+
|
|
258
|
+
**Initial setup:**
|
|
259
|
+
```bash
|
|
260
|
+
npm run archetype:generate # Generate code
|
|
261
|
+
npm run db:push # Create database schema
|
|
262
|
+
npm run db:seed # Add sample data
|
|
263
|
+
npm run dev # Start dev server
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Development loop:**
|
|
267
|
+
```bash
|
|
268
|
+
# Edit archetype/entities/product.ts
|
|
269
|
+
npm run archetype:generate # Regenerate code
|
|
270
|
+
npm run db:push # Update schema
|
|
271
|
+
npm run dev # Test changes
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Documentation & validation:**
|
|
275
|
+
```bash
|
|
276
|
+
npm run archetype:view # View entity relationships
|
|
277
|
+
npm run archetype:docs # Browse API endpoints
|
|
278
|
+
npm run archetype:check # Validate entity definitions
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
217
283
|
## Roadmap
|
|
218
284
|
|
|
219
285
|
- [x] Core entity system with relations
|
package/dist/src/cli.js
CHANGED
|
@@ -301,6 +301,89 @@ function buildHTML(mermaidCode) {
|
|
|
301
301
|
</body>
|
|
302
302
|
</html>`;
|
|
303
303
|
}
|
|
304
|
+
function serveOpenAPIDocs(port = 3334, maxAttempts = 10) {
|
|
305
|
+
// Check if generated/docs/openapi.json exists
|
|
306
|
+
const openapiPath = path.resolve('generated/docs/openapi.json');
|
|
307
|
+
if (!fs.existsSync(openapiPath)) {
|
|
308
|
+
console.error('OpenAPI spec not found at: generated/docs/openapi.json');
|
|
309
|
+
console.error('Run "npx archetype generate" first to generate API documentation');
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
312
|
+
const openapiSpec = fs.readFileSync(openapiPath, 'utf-8');
|
|
313
|
+
const html = `<!DOCTYPE html>
|
|
314
|
+
<html lang="en">
|
|
315
|
+
<head>
|
|
316
|
+
<meta charset="UTF-8">
|
|
317
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
318
|
+
<title>API Documentation - Swagger UI</title>
|
|
319
|
+
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
|
|
320
|
+
<style>
|
|
321
|
+
body { margin: 0; padding: 0; }
|
|
322
|
+
</style>
|
|
323
|
+
</head>
|
|
324
|
+
<body>
|
|
325
|
+
<div id="swagger-ui"></div>
|
|
326
|
+
|
|
327
|
+
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js"></script>
|
|
328
|
+
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-standalone-preset.js"></script>
|
|
329
|
+
<script>
|
|
330
|
+
window.onload = function() {
|
|
331
|
+
window.ui = SwaggerUIBundle({
|
|
332
|
+
spec: ${openapiSpec},
|
|
333
|
+
dom_id: '#swagger-ui',
|
|
334
|
+
deepLinking: true,
|
|
335
|
+
presets: [
|
|
336
|
+
SwaggerUIBundle.presets.apis,
|
|
337
|
+
SwaggerUIStandalonePreset
|
|
338
|
+
],
|
|
339
|
+
plugins: [
|
|
340
|
+
SwaggerUIBundle.plugins.DownloadUrl
|
|
341
|
+
],
|
|
342
|
+
layout: 'StandaloneLayout',
|
|
343
|
+
defaultModelsExpandDepth: 1,
|
|
344
|
+
defaultModelExpandDepth: 1,
|
|
345
|
+
});
|
|
346
|
+
};
|
|
347
|
+
</script>
|
|
348
|
+
</body>
|
|
349
|
+
</html>`;
|
|
350
|
+
const server = http.createServer((req, res) => {
|
|
351
|
+
// Serve OpenAPI JSON spec at /openapi.json
|
|
352
|
+
if (req.url === '/openapi.json') {
|
|
353
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
354
|
+
res.end(openapiSpec);
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
// Serve Swagger UI HTML
|
|
358
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
359
|
+
res.end(html);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
server.on('error', (err) => {
|
|
363
|
+
if (err.code === 'EADDRINUSE') {
|
|
364
|
+
const nextPort = port + 1;
|
|
365
|
+
if (nextPort - 3334 < maxAttempts) {
|
|
366
|
+
console.log(`Port ${port} is in use, trying ${nextPort}...`);
|
|
367
|
+
serveOpenAPIDocs(nextPort, maxAttempts);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
console.error(`Could not find an available port (tried ${3334}-${port})`);
|
|
371
|
+
console.error('Try killing the process using the port:');
|
|
372
|
+
console.error(` lsof -i :3334 | grep LISTEN | awk '{print $2}' | xargs kill -9`);
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
console.error('Server error:', err.message);
|
|
378
|
+
process.exit(1);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
server.listen(port, () => {
|
|
382
|
+
console.log(`http://localhost:${port}`);
|
|
383
|
+
console.log('Ctrl+C to stop');
|
|
384
|
+
openBrowser(`http://localhost:${port}`);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
304
387
|
async function runGenerate(manifest) {
|
|
305
388
|
// Determine template: CLI flag > config > error
|
|
306
389
|
const templateId = templateOverride || manifest.template;
|
|
@@ -457,7 +540,8 @@ function loadJSONManifest(configFile) {
|
|
|
457
540
|
])),
|
|
458
541
|
behaviors: e.behaviors,
|
|
459
542
|
auth: e.auth,
|
|
460
|
-
protected
|
|
543
|
+
// Only include protected if it was explicitly set (for validation)
|
|
544
|
+
protected: e._hasProtected ? e.protected : undefined,
|
|
461
545
|
})),
|
|
462
546
|
database: manifest.database,
|
|
463
547
|
mode: manifest.mode.type,
|
|
@@ -503,6 +587,10 @@ async function main() {
|
|
|
503
587
|
const erd = (0, erd_ir_1.generateERDFromIR)(manifest);
|
|
504
588
|
serveERD(erd);
|
|
505
589
|
}
|
|
590
|
+
else if (command === 'docs') {
|
|
591
|
+
// Serve OpenAPI documentation
|
|
592
|
+
serveOpenAPIDocs();
|
|
593
|
+
}
|
|
506
594
|
else if (command === 'init') {
|
|
507
595
|
// Run the TUI init flow
|
|
508
596
|
await (0, init_1.init)({ yes: yesFlag, headless: headlessFlag });
|
|
@@ -520,6 +608,7 @@ async function main() {
|
|
|
520
608
|
console.log(' archetype generate [config] - Generate code from entities');
|
|
521
609
|
console.log(' archetype validate [config] - Validate manifest without generating');
|
|
522
610
|
console.log(' archetype view [config] - View ERD diagram in browser');
|
|
611
|
+
console.log(' archetype docs - View OpenAPI/Swagger documentation in browser');
|
|
523
612
|
console.log(' archetype mcp - Start MCP server (for Claude Desktop/Code)');
|
|
524
613
|
console.log('');
|
|
525
614
|
console.log('Flags:');
|
package/dist/src/entity.d.ts
CHANGED
|
@@ -131,6 +131,8 @@ export interface EntityIR {
|
|
|
131
131
|
auth: boolean;
|
|
132
132
|
/** Normalized protection config for CRUD operations */
|
|
133
133
|
protected: ProtectedIR;
|
|
134
|
+
/** Whether protected was explicitly set (for validation) */
|
|
135
|
+
_hasProtected: boolean;
|
|
134
136
|
/** External API source (optional - inherits from manifest if not specified) */
|
|
135
137
|
source?: ExternalSourceConfig;
|
|
136
138
|
/** Normalized hooks config */
|
package/dist/src/entity.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../src/entity.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../src/entity.ts"],"names":[],"mappings":"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"}
|
package/dist/src/entity.js
CHANGED
|
@@ -74,6 +74,7 @@ function compileEntity(name, definition) {
|
|
|
74
74
|
},
|
|
75
75
|
auth: definition.auth || false,
|
|
76
76
|
protected: normalizeProtected(definition.protected),
|
|
77
|
+
_hasProtected: definition.protected !== undefined && definition.protected !== false,
|
|
77
78
|
source: definition.source,
|
|
78
79
|
hooks: normalizeHooks(definition.hooks),
|
|
79
80
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../../src/init/dependencies.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAC1D,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAA;AAC1C,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE1E,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,IAAI,EAAE,OAAO,CAAA;IACb,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACrB,eAAe,EAAE,OAAO,CAAA;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAGD,eAAO,MAAM,gBAAgB,UAS5B,CAAA;AAGD,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../../src/init/dependencies.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;AAC1D,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAA;AAC1C,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE1E,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,IAAI,EAAE,OAAO,CAAA;IACb,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACrB,eAAe,EAAE,OAAO,CAAA;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAGD,eAAO,MAAM,gBAAgB,UAS5B,CAAA;AAGD,eAAO,MAAM,mBAAmB,UAI/B,CAAA;AAGD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAa5F,CAAA;AAGD,eAAO,MAAM,gBAAgB;;;CAG5B,CAAA;AAGD,eAAO,MAAM,oBAAoB,UAQhC,CAAA;AAGD,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAiCzF;AAGD,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,QAAiB,GAAG,UAAU,CAoB5F"}
|
|
@@ -18,6 +18,8 @@ exports.coreDependencies = [
|
|
|
18
18
|
// Dev dependencies (always installed)
|
|
19
19
|
exports.coreDevDependencies = [
|
|
20
20
|
'drizzle-kit',
|
|
21
|
+
'tsx', // For running seed scripts
|
|
22
|
+
'vitest', // For running tests
|
|
21
23
|
];
|
|
22
24
|
// Database-specific dependencies
|
|
23
25
|
exports.databaseDependencies = {
|
|
@@ -7,6 +7,7 @@ export declare function getTrpcServerTemplate(config: InitConfig): string;
|
|
|
7
7
|
export declare function getTrpcClientTemplate(): string;
|
|
8
8
|
export declare function getProvidersTemplate(): string;
|
|
9
9
|
export declare function getApiRouteTemplate(config: InitConfig): string;
|
|
10
|
+
export declare function getVitestConfigTemplate(structure: ProjectStructure): string;
|
|
10
11
|
export declare function getDrizzleConfigTemplate(database: DatabaseType): string;
|
|
11
12
|
export declare function getAuthTemplate(config: InitConfig): string;
|
|
12
13
|
export declare function getAuthRouteTemplate(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/init/templates.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAI9D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA2G5D;AAGD,wBAAgB,qBAAqB,IAAI,MAAM,CAe9C;AAGD,wBAAgB,wBAAwB,IAAI,MAAM,CAejD;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CA2B5D;AAGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAyGhE;AAGD,wBAAgB,qBAAqB,IAAI,MAAM,CAM9C;AAGD,wBAAgB,oBAAoB,IAAI,MAAM,CAyB7C;AAGD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAgC9D;AAGD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAsBvE;AAGD,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA6E1D;AAGD,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAkChE;AAGD,wBAAgB,oBAAoB,IAAI,MAAM,CA6B7C;AAGD,wBAAgB,mBAAmB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/init/templates.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAI9D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA2G5D;AAGD,wBAAgB,qBAAqB,IAAI,MAAM,CAe9C;AAGD,wBAAgB,wBAAwB,IAAI,MAAM,CAejD;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CA2B5D;AAGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAyGhE;AAGD,wBAAgB,qBAAqB,IAAI,MAAM,CAM9C;AAGD,wBAAgB,oBAAoB,IAAI,MAAM,CAyB7C;AAGD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAgC9D;AAGD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,CAiB3E;AAGD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAsBvE;AAGD,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA6E1D;AAGD,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAkChE;AAGD,wBAAgB,oBAAoB,IAAI,MAAM,CA6B7C;AAGD,wBAAgB,mBAAmB,IAAI,MAAM,CAyN5C;AAGD,wBAAgB,sBAAsB,IAAI,MAAM,CAyM/C;AAGD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,GAAG,YAAY,EAAE,CAwFnG;AAGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBhF"}
|
|
@@ -9,6 +9,7 @@ exports.getTrpcServerTemplate = getTrpcServerTemplate;
|
|
|
9
9
|
exports.getTrpcClientTemplate = getTrpcClientTemplate;
|
|
10
10
|
exports.getProvidersTemplate = getProvidersTemplate;
|
|
11
11
|
exports.getApiRouteTemplate = getApiRouteTemplate;
|
|
12
|
+
exports.getVitestConfigTemplate = getVitestConfigTemplate;
|
|
12
13
|
exports.getDrizzleConfigTemplate = getDrizzleConfigTemplate;
|
|
13
14
|
exports.getAuthTemplate = getAuthTemplate;
|
|
14
15
|
exports.getAuthRouteTemplate = getAuthRouteTemplate;
|
|
@@ -350,6 +351,25 @@ const handler = (req: Request) =>
|
|
|
350
351
|
export { handler as GET, handler as POST }
|
|
351
352
|
`;
|
|
352
353
|
}
|
|
354
|
+
// vitest.config.ts
|
|
355
|
+
function getVitestConfigTemplate(structure) {
|
|
356
|
+
const prefix = structure.useSrcDir ? './src/' : './';
|
|
357
|
+
return `import { defineConfig } from 'vitest/config'
|
|
358
|
+
import path from 'path'
|
|
359
|
+
|
|
360
|
+
export default defineConfig({
|
|
361
|
+
test: {
|
|
362
|
+
globals: true,
|
|
363
|
+
environment: 'node',
|
|
364
|
+
},
|
|
365
|
+
resolve: {
|
|
366
|
+
alias: {
|
|
367
|
+
'@': path.resolve(__dirname, '${prefix}'),
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
})
|
|
371
|
+
`;
|
|
372
|
+
}
|
|
353
373
|
// drizzle.config.ts
|
|
354
374
|
function getDrizzleConfigTemplate(database) {
|
|
355
375
|
const dialectMap = {
|
|
@@ -614,11 +634,20 @@ npm run db:push
|
|
|
614
634
|
## Available Commands
|
|
615
635
|
|
|
616
636
|
\`\`\`bash
|
|
637
|
+
# Archetype commands
|
|
617
638
|
npm run archetype:generate # Generate code from entities
|
|
618
|
-
npm run archetype:view # View ERD in browser
|
|
639
|
+
npm run archetype:view # View ERD diagram in browser
|
|
640
|
+
npm run archetype:docs # View API docs (Swagger UI)
|
|
641
|
+
npm run archetype:check # Validate manifest without generating
|
|
642
|
+
|
|
643
|
+
# Database commands
|
|
619
644
|
npm run db:push # Push schema to database
|
|
620
|
-
npm run db:studio # Open Drizzle Studio
|
|
621
|
-
|
|
645
|
+
npm run db:studio # Open Drizzle Studio (database GUI)
|
|
646
|
+
npm run db:seed # Seed database with sample data
|
|
647
|
+
npm run db:seed:reset # Reset database and seed
|
|
648
|
+
|
|
649
|
+
# Testing
|
|
650
|
+
npm run test:api # Run generated API tests
|
|
622
651
|
\`\`\`
|
|
623
652
|
|
|
624
653
|
## Examples
|
|
@@ -851,20 +880,20 @@ When discussing code, use \`file:line\` format: \`archetype/entities/user.ts:12\
|
|
|
851
880
|
|
|
852
881
|
## Commands Reference
|
|
853
882
|
\`\`\`bash
|
|
854
|
-
# Generate
|
|
855
|
-
npm run archetype:generate
|
|
856
|
-
|
|
857
|
-
# View
|
|
858
|
-
npm run archetype:
|
|
859
|
-
|
|
860
|
-
# Push schema to database (full mode)
|
|
861
|
-
npm run db:push
|
|
883
|
+
# Archetype - Generate & View
|
|
884
|
+
npm run archetype:generate # Generate code from entities
|
|
885
|
+
npm run archetype:view # View ERD diagram in browser
|
|
886
|
+
npm run archetype:docs # View API docs (Swagger UI)
|
|
887
|
+
npm run archetype:check # Validate manifest without generating
|
|
862
888
|
|
|
863
|
-
#
|
|
864
|
-
npm run db:
|
|
889
|
+
# Database (full mode only)
|
|
890
|
+
npm run db:push # Push schema to database
|
|
891
|
+
npm run db:studio # Open Drizzle Studio (database GUI)
|
|
892
|
+
npm run db:seed # Seed database with sample data
|
|
893
|
+
npm run db:seed:reset # Reset database and seed
|
|
865
894
|
|
|
866
|
-
#
|
|
867
|
-
|
|
895
|
+
# Testing
|
|
896
|
+
npm run test:api # Run generated API tests
|
|
868
897
|
\`\`\`
|
|
869
898
|
|
|
870
899
|
## Examples
|
|
@@ -932,6 +961,8 @@ function getAllTemplateFiles(config, structure) {
|
|
|
932
961
|
const files = [
|
|
933
962
|
// Config - always needed
|
|
934
963
|
{ path: 'archetype.config.ts', content: getConfigTemplate(config) },
|
|
964
|
+
// Vitest config for path aliases
|
|
965
|
+
{ path: 'vitest.config.ts', content: getVitestConfigTemplate(structure) },
|
|
935
966
|
// Gitignore - always needed
|
|
936
967
|
{ path: '.gitignore', content: getGitignoreTemplate() },
|
|
937
968
|
// AI assistant guidance files
|
|
@@ -993,13 +1024,19 @@ function getAllTemplateFiles(config, structure) {
|
|
|
993
1024
|
// package.json scripts to add
|
|
994
1025
|
function getPackageJsonScripts(config) {
|
|
995
1026
|
const scripts = {
|
|
1027
|
+
// Archetype - core commands
|
|
996
1028
|
'archetype:generate': 'archetype generate',
|
|
997
1029
|
'archetype:view': 'archetype view',
|
|
1030
|
+
'archetype:docs': 'archetype docs',
|
|
1031
|
+
'archetype:check': 'archetype validate',
|
|
998
1032
|
};
|
|
999
1033
|
// Only add database scripts for full mode
|
|
1000
1034
|
if (config.mode === 'full') {
|
|
1001
1035
|
scripts['db:push'] = 'drizzle-kit push';
|
|
1002
1036
|
scripts['db:studio'] = 'drizzle-kit studio';
|
|
1037
|
+
scripts['db:seed'] = 'tsx generated/seeds/run.ts';
|
|
1038
|
+
scripts['db:seed:reset'] = 'tsx generated/seeds/run.ts --reset';
|
|
1039
|
+
scripts['test:api'] = 'vitest run generated/tests';
|
|
1003
1040
|
}
|
|
1004
1041
|
return scripts;
|
|
1005
1042
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/json/parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAc,MAAM,WAAW,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAmB,OAAO,EAAE,MAAM,WAAW,CAAA;AAC3E,OAAO,EAAE,UAAU,EAA6B,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EACL,SAAS,EACT,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,SAAS,EACV,MAAM,SAAS,CAAA;AAEhB;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CA8C5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,cAAc,CAMxE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,GAAG,oBAAoB,CAuBxF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,WAAW,CAWtE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAuBpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/json/parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAc,MAAM,WAAW,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAmB,OAAO,EAAE,MAAM,WAAW,CAAA;AAC3E,OAAO,EAAE,UAAU,EAA6B,MAAM,aAAa,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EACL,SAAS,EACT,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,SAAS,EACV,MAAM,SAAS,CAAA;AAEhB;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CA8C5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,cAAc,CAMxE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,kBAAkB,GAAG,oBAAoB,CAuBxF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,WAAW,CAWtE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAuBpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,QAAQ,CAuC5D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,UAAU,CAkEzE;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAIpF"}
|
package/dist/src/json/parser.js
CHANGED
|
@@ -215,6 +215,7 @@ function parseEntityJSON(entity) {
|
|
|
215
215
|
behaviors,
|
|
216
216
|
auth: entity.auth || false,
|
|
217
217
|
protected: parseProtectedJSON(entity.protected),
|
|
218
|
+
_hasProtected: entity.protected !== undefined && entity.protected !== false,
|
|
218
219
|
source,
|
|
219
220
|
hooks: parseHooksJSON(entity.hooks),
|
|
220
221
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../../../src/templates/nextjs-drizzle-trpc/generators/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../../../src/templates/nextjs-drizzle-trpc/generators/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,yBAAyB,CAAA;AA0WvE;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,SAwC3B,CAAA"}
|
|
@@ -116,9 +116,9 @@ function generateMockValue(fieldName, field, index) {
|
|
|
116
116
|
return `faker ? faker.datatype.boolean() : i % 2 === 0`;
|
|
117
117
|
case 'date':
|
|
118
118
|
if (lowerName.includes('birth')) {
|
|
119
|
-
return `faker ? faker.date.birthdate() : new Date(1990 + (i % 30), i % 12, 1 + (i % 28))`;
|
|
119
|
+
return `faker ? faker.date.birthdate().toISOString() : new Date(1990 + (i % 30), i % 12, 1 + (i % 28)).toISOString()`;
|
|
120
120
|
}
|
|
121
|
-
return `faker ? faker.date.recent() : new Date()`;
|
|
121
|
+
return `faker ? faker.date.recent().toISOString() : new Date().toISOString()`;
|
|
122
122
|
case 'enum':
|
|
123
123
|
const enumValues = field.enumValues || [];
|
|
124
124
|
return `faker ? faker.helpers.arrayElement(${JSON.stringify(enumValues)}) : ${JSON.stringify(enumValues)}[i % ${enumValues.length}]`;
|
|
@@ -161,6 +161,8 @@ function generateEntitySeedFunction(entity) {
|
|
|
161
161
|
lines.push(` }`);
|
|
162
162
|
lines.push(``);
|
|
163
163
|
lines.push(` const data = Array.from({ length: count }, (_, i) => ({`);
|
|
164
|
+
// Add ID field
|
|
165
|
+
lines.push(` id: faker ? faker.string.uuid() : \`${entityName.toLowerCase()}-\${Date.now()}-\${i}\`,`);
|
|
164
166
|
// Generate field values
|
|
165
167
|
for (const [fieldName, field] of seedableFields) {
|
|
166
168
|
const value = generateMockValue(fieldName, field, 0);
|
|
@@ -173,8 +175,8 @@ function generateEntitySeedFunction(entity) {
|
|
|
173
175
|
}
|
|
174
176
|
// Add timestamps if enabled
|
|
175
177
|
if (entity.behaviors.timestamps) {
|
|
176
|
-
lines.push(` createdAt: faker ? faker.date.recent({ days: 30 }) : new Date(),`);
|
|
177
|
-
lines.push(` updatedAt: faker ? faker.date.recent({ days: 7 }) : new Date(),`);
|
|
178
|
+
lines.push(` createdAt: faker ? faker.date.recent({ days: 30 }).toISOString() : new Date().toISOString(),`);
|
|
179
|
+
lines.push(` updatedAt: faker ? faker.date.recent({ days: 7 }).toISOString() : new Date().toISOString(),`);
|
|
178
180
|
}
|
|
179
181
|
lines.push(` }))`);
|
|
180
182
|
lines.push(``);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../../../../src/templates/nextjs-drizzle-trpc/generators/test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../../../../src/templates/nextjs-drizzle-trpc/generators/test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,yBAAyB,CAAA;AAogBvE;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,SAuB3B,CAAA"}
|
|
@@ -110,7 +110,10 @@ function generateInvalidValue(fieldName, field) {
|
|
|
110
110
|
}
|
|
111
111
|
const minLength = field.validations.find(v => v.type === 'minLength');
|
|
112
112
|
if (minLength) {
|
|
113
|
-
|
|
113
|
+
const minVal = minLength.value;
|
|
114
|
+
// Generate a string shorter than the minimum (empty string if min is 1)
|
|
115
|
+
const invalidStr = minVal > 1 ? 'x'.repeat(minVal - 1) : '';
|
|
116
|
+
return { value: `'${invalidStr}'`, reason: `below minimum length of ${minLength.value}` };
|
|
114
117
|
}
|
|
115
118
|
const maxLength = field.validations.find(v => v.type === 'maxLength');
|
|
116
119
|
if (maxLength) {
|
|
@@ -165,16 +168,14 @@ function generateEntityTest(entity, manifest) {
|
|
|
165
168
|
const lines = [];
|
|
166
169
|
// Imports
|
|
167
170
|
lines.push(`import { describe, it, expect, beforeEach } from 'vitest'`);
|
|
168
|
-
lines.push(`import { appRouter } from '
|
|
169
|
-
lines.push(`import {
|
|
170
|
-
lines.push(``);
|
|
171
|
-
lines.push(`// Create tRPC caller for testing`);
|
|
172
|
-
lines.push(`const createCaller = createCallerFactory(appRouter)`);
|
|
171
|
+
lines.push(`import { appRouter } from '../trpc/routers'`);
|
|
172
|
+
lines.push(`import { db } from '@/server/db'`);
|
|
173
173
|
lines.push(``);
|
|
174
174
|
// Mock contexts
|
|
175
175
|
if (hasAuth) {
|
|
176
176
|
lines.push(`// Mock authenticated context`);
|
|
177
177
|
lines.push(`const mockAuthContext = {`);
|
|
178
|
+
lines.push(` db,`);
|
|
178
179
|
lines.push(` session: {`);
|
|
179
180
|
lines.push(` user: { id: 'test-user-123', email: 'test@example.com', name: 'Test User' }`);
|
|
180
181
|
lines.push(` }`);
|
|
@@ -183,14 +184,15 @@ function generateEntityTest(entity, manifest) {
|
|
|
183
184
|
}
|
|
184
185
|
lines.push(`// Mock unauthenticated context`);
|
|
185
186
|
lines.push(`const mockPublicContext = {`);
|
|
187
|
+
lines.push(` db,`);
|
|
186
188
|
lines.push(` session: null`);
|
|
187
189
|
lines.push(`}`);
|
|
188
190
|
lines.push(``);
|
|
189
191
|
// Test suite
|
|
190
192
|
lines.push(`describe('${entityName} Router', () => {`);
|
|
191
|
-
lines.push(` const publicCaller = createCaller(mockPublicContext)`);
|
|
193
|
+
lines.push(` const publicCaller = appRouter.createCaller(mockPublicContext)`);
|
|
192
194
|
if (hasAuth) {
|
|
193
|
-
lines.push(` const authCaller = createCaller(mockAuthContext)`);
|
|
195
|
+
lines.push(` const authCaller = appRouter.createCaller(mockAuthContext)`);
|
|
194
196
|
}
|
|
195
197
|
lines.push(``);
|
|
196
198
|
// Valid test data
|
|
@@ -340,10 +342,9 @@ function generateEntityTest(entity, manifest) {
|
|
|
340
342
|
lines.push(` })`);
|
|
341
343
|
lines.push(``);
|
|
342
344
|
const getCaller = entity.protected.get ? 'authCaller' : 'publicCaller';
|
|
343
|
-
lines.push(` it('should
|
|
344
|
-
lines.push(` await
|
|
345
|
-
lines.push(`
|
|
346
|
-
lines.push(` ).rejects.toThrow()`);
|
|
345
|
+
lines.push(` it('should return null for non-existent ID', async () => {`);
|
|
346
|
+
lines.push(` const result = await ${getCaller}.${routerName}.get({ id: 'non-existent-id' })`);
|
|
347
|
+
lines.push(` expect(result).toBeNull()`);
|
|
347
348
|
lines.push(` })`);
|
|
348
349
|
lines.push(``);
|
|
349
350
|
lines.push(` })`);
|
|
@@ -378,7 +379,7 @@ function generateEntityTest(entity, manifest) {
|
|
|
378
379
|
lines.push(``);
|
|
379
380
|
lines.push(` expect(result.${firstField}).toBe(updateData.${firstField})`);
|
|
380
381
|
if (hasTimestamps) {
|
|
381
|
-
lines.push(` expect(new Date(result.updatedAt).getTime()).
|
|
382
|
+
lines.push(` expect(new Date(result.updatedAt).getTime()).toBeGreaterThanOrEqual(new Date(created.updatedAt).getTime())`);
|
|
382
383
|
}
|
|
383
384
|
}
|
|
384
385
|
lines.push(` })`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/validation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAuC,MAAM,eAAe,CAAA;AAEjF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,KAAK,EAAE,OAAO,CAAA;IACd,mCAAmC;IACnC,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,yCAAyC;IACzC,QAAQ,EAAE,eAAe,EAAE,CAAA;CAC5B;AAGD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;CAgClB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/validation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAuC,MAAM,eAAe,CAAA;AAEjF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,KAAK,EAAE,OAAO,CAAA;IACd,mCAAmC;IACnC,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,yCAAyC;IACzC,QAAQ,EAAE,eAAe,EAAE,CAAA;CAC5B;AAGD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;CAgClB,CAAA;AA8PV;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB,CA2DzE"}
|
|
@@ -139,17 +139,9 @@ function validateEntity(entity, entityNames, authEnabled) {
|
|
|
139
139
|
errors.push(...validateRelation(relationName, relation, entity.name, entityNames));
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
// Check protected requires auth
|
|
142
|
+
// Check protected requires auth (only if explicitly set)
|
|
143
143
|
if (entity.protected !== undefined && entity.protected !== false) {
|
|
144
|
-
|
|
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
|
|
144
|
+
// Validate protected value format
|
|
153
145
|
const validProtectedStrings = ['write', 'all'];
|
|
154
146
|
if (typeof entity.protected !== 'boolean' &&
|
|
155
147
|
typeof entity.protected !== 'object' &&
|
|
@@ -161,6 +153,15 @@ function validateEntity(entity, entityNames, authEnabled) {
|
|
|
161
153
|
suggestion: `Use one of: true, false, 'write', 'all', or an object with list/get/create/update/remove`,
|
|
162
154
|
});
|
|
163
155
|
}
|
|
156
|
+
// Only require auth if protected is explicitly enabled
|
|
157
|
+
if (!authEnabled) {
|
|
158
|
+
errors.push({
|
|
159
|
+
code: exports.ValidationCodes.AUTH_REQUIRED_FOR_PROTECTED,
|
|
160
|
+
path: `${path}.protected`,
|
|
161
|
+
message: `Entity '${entity.name}' has protected operations but auth is not enabled`,
|
|
162
|
+
suggestion: `Add auth: { enabled: true } to manifest, or remove protected from entity`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
164
165
|
}
|
|
165
166
|
// Validate external source
|
|
166
167
|
if (entity.source && !entity.source.baseUrl) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archetype-engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Type-safe backend generator for Next.js. Define entities once, get Drizzle schemas, tRPC APIs, Zod validation, and React hooks instantly.",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|