@claudetools/tools 0.8.11 → 0.9.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.
Files changed (75) hide show
  1. package/dist/codedna/generators/astro.d.ts +18 -0
  2. package/dist/codedna/generators/astro.js +91 -0
  3. package/dist/codedna/generators/authjs.d.ts +18 -0
  4. package/dist/codedna/generators/authjs.js +68 -0
  5. package/dist/codedna/generators/better-auth.d.ts +18 -0
  6. package/dist/codedna/generators/better-auth.js +62 -0
  7. package/dist/codedna/generators/drizzle-orm.d.ts +18 -0
  8. package/dist/codedna/generators/drizzle-orm.js +65 -0
  9. package/dist/codedna/generators/elysia-api.d.ts +12 -0
  10. package/dist/codedna/generators/elysia-api.js +64 -0
  11. package/dist/codedna/generators/hono-api.d.ts +12 -0
  12. package/dist/codedna/generators/hono-api.js +64 -0
  13. package/dist/codedna/generators/lucia-auth.d.ts +18 -0
  14. package/dist/codedna/generators/lucia-auth.js +69 -0
  15. package/dist/codedna/generators/prisma.d.ts +18 -0
  16. package/dist/codedna/generators/prisma.js +64 -0
  17. package/dist/codedna/generators/react-router-v7.d.ts +18 -0
  18. package/dist/codedna/generators/react-router-v7.js +77 -0
  19. package/dist/codedna/generators/react19-shadcn.d.ts +21 -0
  20. package/dist/codedna/generators/react19-shadcn.js +367 -0
  21. package/dist/codedna/generators/sveltekit.d.ts +18 -0
  22. package/dist/codedna/generators/sveltekit.js +73 -0
  23. package/dist/codedna/generators/tanstack-start-drizzle.d.ts +92 -0
  24. package/dist/codedna/generators/tanstack-start-drizzle.js +824 -0
  25. package/dist/codedna/generators/trpc-api.d.ts +12 -0
  26. package/dist/codedna/generators/trpc-api.js +64 -0
  27. package/dist/codedna/index.d.ts +31 -0
  28. package/dist/codedna/index.js +39 -0
  29. package/dist/codedna/kappa-api-generator.d.ts +89 -0
  30. package/dist/codedna/kappa-api-generator.js +493 -0
  31. package/dist/codedna/kappa-ast.d.ts +552 -0
  32. package/dist/codedna/kappa-ast.js +141 -0
  33. package/dist/codedna/kappa-cli.d.ts +2 -0
  34. package/dist/codedna/kappa-cli.js +302 -0
  35. package/dist/codedna/kappa-component-generator.d.ts +47 -0
  36. package/dist/codedna/kappa-component-generator.js +295 -0
  37. package/dist/codedna/kappa-design-generator.d.ts +52 -0
  38. package/dist/codedna/kappa-design-generator.js +365 -0
  39. package/dist/codedna/kappa-drizzle-generator.d.ts +45 -0
  40. package/dist/codedna/kappa-drizzle-generator.js +355 -0
  41. package/dist/codedna/kappa-form-generator.d.ts +51 -0
  42. package/dist/codedna/kappa-form-generator.js +319 -0
  43. package/dist/codedna/kappa-lexer.d.ts +268 -0
  44. package/dist/codedna/kappa-lexer.js +757 -0
  45. package/dist/codedna/kappa-page-generator.d.ts +57 -0
  46. package/dist/codedna/kappa-page-generator.js +338 -0
  47. package/dist/codedna/kappa-parser.d.ts +261 -0
  48. package/dist/codedna/kappa-parser.js +2547 -0
  49. package/dist/codedna/kappa-provenance.d.ts +101 -0
  50. package/dist/codedna/kappa-provenance.js +199 -0
  51. package/dist/codedna/kappa-types-generator.d.ts +37 -0
  52. package/dist/codedna/kappa-types-generator.js +159 -0
  53. package/dist/codedna/kappa-validator.d.ts +86 -0
  54. package/dist/codedna/kappa-validator.js +638 -0
  55. package/dist/codedna/kappa-zod-generator.d.ts +32 -0
  56. package/dist/codedna/kappa-zod-generator.js +216 -0
  57. package/dist/handlers/kappa-handlers.d.ts +116 -0
  58. package/dist/handlers/kappa-handlers.js +465 -0
  59. package/dist/handlers/tool-handlers.js +121 -0
  60. package/dist/templates/claude-md.d.ts +1 -1
  61. package/dist/templates/claude-md.js +166 -9
  62. package/dist/tools.js +199 -0
  63. package/docs/research/2026-01-02-codedna-il-specification.md +639 -0
  64. package/docs/research/2026-01-02-codedna-v2-research.md +943 -0
  65. package/docs/research/2026-01-02-computation-foundations.md +564 -0
  66. package/docs/research/2026-01-02-hardware-description.md +814 -0
  67. package/docs/research/2026-01-02-kappa-specification.md +697 -0
  68. package/docs/research/2026-01-02-kappa-tanstack-example.md +527 -0
  69. package/docs/research/2026-01-02-kappa-v2-synthesis.md +406 -0
  70. package/docs/research/2026-01-02-kappa-v2.5-specification.md +1218 -0
  71. package/docs/research/2026-01-02-kappa-v3-specification.md +1864 -0
  72. package/docs/research/2026-01-02-kappa-whitepaper.md +662 -0
  73. package/docs/research/2026-01-02-logic-constraint.md +731 -0
  74. package/docs/research/2026-01-02-quantum-computation.md +635 -0
  75. package/package.json +4 -2
@@ -0,0 +1,824 @@
1
+ // =============================================================================
2
+ // Tanstack Start + Drizzle ORM Generator
3
+ // =============================================================================
4
+ //
5
+ // Generates complete full-stack application with:
6
+ // - Tanstack Start (React framework with SSR/CSR)
7
+ // - Drizzle ORM (type-safe SQL)
8
+ // - File-based routing
9
+ // - Type-safe data loading
10
+ // - Server actions for mutations
11
+ // - Multiple database support (PostgreSQL, MySQL, SQLite)
12
+ // - Cloudflare and Node deployment
13
+ //
14
+ import { BaseGenerator } from './base.js';
15
+ import { TemplateEngine, buildContext } from '../template-engine.js';
16
+ export class TanstackStartDrizzleGenerator extends BaseGenerator {
17
+ engine;
18
+ dbOptions;
19
+ constructor(options = {}) {
20
+ super();
21
+ this.engine = new TemplateEngine();
22
+ this.dbOptions = {
23
+ database: options.database || 'postgresql',
24
+ deployment: options.deployment || 'cloudflare',
25
+ ssr: options.ssr ?? true,
26
+ auth: options.auth ?? false,
27
+ ...options,
28
+ };
29
+ }
30
+ /**
31
+ * Generate complete Tanstack Start + Drizzle application
32
+ */
33
+ async generate(entity) {
34
+ const files = [];
35
+ const context = buildContext(entity, this.dbOptions);
36
+ // 1. Drizzle schema
37
+ files.push(await this.generateSchema(entity, context));
38
+ // 2. Drizzle migrations
39
+ files.push(await this.generateMigration(entity, context));
40
+ // 3. Database client configuration
41
+ files.push(await this.generateDbClient(context));
42
+ // 4. CRUD operations (queries + mutations)
43
+ files.push(await this.generateQueries(entity, context));
44
+ files.push(await this.generateMutations(entity, context));
45
+ // 5. Tanstack Start routes
46
+ files.push(await this.generateIndexRoute(entity, context)); // List view
47
+ files.push(await this.generateDetailRoute(entity, context)); // Detail view
48
+ files.push(await this.generateCreateRoute(entity, context)); // Create form
49
+ files.push(await this.generateEditRoute(entity, context)); // Edit form
50
+ // 6. React components
51
+ files.push(await this.generateListComponent(entity, context));
52
+ files.push(await this.generateFormComponent(entity, context));
53
+ // 7. Type definitions
54
+ files.push(await this.generateTypes(entity, context));
55
+ // 8. Configuration files
56
+ if (this.dbOptions.deployment === 'cloudflare') {
57
+ files.push(await this.generateWranglerConfig(context));
58
+ }
59
+ files.push(await this.generateDrizzleConfig(context));
60
+ files.push(await this.generatePackageJson(context));
61
+ return files;
62
+ }
63
+ /**
64
+ * Generate Drizzle schema definition
65
+ */
66
+ async generateSchema(entity, context) {
67
+ const template = this.getSchemaTemplate();
68
+ const content = this.engine.render(template, context);
69
+ return {
70
+ path: `src/db/schema/${entity.name.toLowerCase()}.ts`,
71
+ content,
72
+ language: 'typescript',
73
+ };
74
+ }
75
+ /**
76
+ * Generate database migration
77
+ */
78
+ async generateMigration(entity, context) {
79
+ const template = this.getMigrationTemplate();
80
+ const content = this.engine.render(template, context);
81
+ const timestamp = new Date().getTime();
82
+ return {
83
+ path: `drizzle/migrations/${timestamp}_create_${entity.name.toLowerCase()}.sql`,
84
+ content,
85
+ language: 'sql',
86
+ };
87
+ }
88
+ /**
89
+ * Generate database client configuration
90
+ */
91
+ async generateDbClient(context) {
92
+ const template = this.getDbClientTemplate();
93
+ const content = this.engine.render(template, context);
94
+ return {
95
+ path: 'src/db/client.ts',
96
+ content,
97
+ language: 'typescript',
98
+ };
99
+ }
100
+ /**
101
+ * Generate type-safe query functions
102
+ */
103
+ async generateQueries(entity, context) {
104
+ const template = this.getQueriesTemplate();
105
+ const content = this.engine.render(template, context);
106
+ return {
107
+ path: `src/queries/${entity.name.toLowerCase()}.ts`,
108
+ content,
109
+ language: 'typescript',
110
+ };
111
+ }
112
+ /**
113
+ * Generate server action mutations
114
+ */
115
+ async generateMutations(entity, context) {
116
+ const template = this.getMutationsTemplate();
117
+ const content = this.engine.render(template, context);
118
+ return {
119
+ path: `src/mutations/${entity.name.toLowerCase()}.ts`,
120
+ content,
121
+ language: 'typescript',
122
+ };
123
+ }
124
+ /**
125
+ * Generate index route (list view)
126
+ */
127
+ async generateIndexRoute(entity, context) {
128
+ const template = this.getIndexRouteTemplate();
129
+ const content = this.engine.render(template, context);
130
+ return {
131
+ path: `src/routes/${entity.name.toLowerCase()}/index.tsx`,
132
+ content,
133
+ language: 'typescript',
134
+ };
135
+ }
136
+ /**
137
+ * Generate detail route
138
+ */
139
+ async generateDetailRoute(entity, context) {
140
+ const template = this.getDetailRouteTemplate();
141
+ const content = this.engine.render(template, context);
142
+ return {
143
+ path: `src/routes/${entity.name.toLowerCase()}/$id.tsx`,
144
+ content,
145
+ language: 'typescript',
146
+ };
147
+ }
148
+ /**
149
+ * Generate create route
150
+ */
151
+ async generateCreateRoute(entity, context) {
152
+ const template = this.getCreateRouteTemplate();
153
+ const content = this.engine.render(template, context);
154
+ return {
155
+ path: `src/routes/${entity.name.toLowerCase()}/create.tsx`,
156
+ content,
157
+ language: 'typescript',
158
+ };
159
+ }
160
+ /**
161
+ * Generate edit route
162
+ */
163
+ async generateEditRoute(entity, context) {
164
+ const template = this.getEditRouteTemplate();
165
+ const content = this.engine.render(template, context);
166
+ return {
167
+ path: `src/routes/${entity.name.toLowerCase()}/$id/edit.tsx`,
168
+ content,
169
+ language: 'typescript',
170
+ };
171
+ }
172
+ /**
173
+ * Generate list component
174
+ */
175
+ async generateListComponent(entity, context) {
176
+ const template = this.getListComponentTemplate();
177
+ const content = this.engine.render(template, context);
178
+ return {
179
+ path: `src/components/${entity.name}List.tsx`,
180
+ content,
181
+ language: 'typescript',
182
+ };
183
+ }
184
+ /**
185
+ * Generate form component
186
+ */
187
+ async generateFormComponent(entity, context) {
188
+ const template = this.getFormComponentTemplate();
189
+ const content = this.engine.render(template, context);
190
+ return {
191
+ path: `src/components/${entity.name}Form.tsx`,
192
+ content,
193
+ language: 'typescript',
194
+ };
195
+ }
196
+ /**
197
+ * Generate TypeScript type definitions
198
+ */
199
+ async generateTypes(entity, context) {
200
+ const template = this.getTypesTemplate();
201
+ const content = this.engine.render(template, context);
202
+ return {
203
+ path: `src/types/${entity.name.toLowerCase()}.ts`,
204
+ content,
205
+ language: 'typescript',
206
+ };
207
+ }
208
+ /**
209
+ * Generate Wrangler configuration for Cloudflare
210
+ */
211
+ async generateWranglerConfig(context) {
212
+ const template = this.getWranglerConfigTemplate();
213
+ const content = this.engine.render(template, context);
214
+ return {
215
+ path: 'wrangler.toml',
216
+ content,
217
+ language: 'toml',
218
+ };
219
+ }
220
+ /**
221
+ * Generate Drizzle configuration
222
+ */
223
+ async generateDrizzleConfig(context) {
224
+ const template = this.getDrizzleConfigTemplate();
225
+ const content = this.engine.render(template, context);
226
+ return {
227
+ path: 'drizzle.config.ts',
228
+ content,
229
+ language: 'typescript',
230
+ };
231
+ }
232
+ /**
233
+ * Generate package.json with dependencies
234
+ */
235
+ async generatePackageJson(context) {
236
+ const template = this.getPackageJsonTemplate();
237
+ const content = this.engine.render(template, context);
238
+ return {
239
+ path: 'package.json',
240
+ content,
241
+ language: 'json',
242
+ };
243
+ }
244
+ // =============================================================================
245
+ // Templates
246
+ // =============================================================================
247
+ getSchemaTemplate() {
248
+ return `// {{ entity.name }} Drizzle Schema
249
+ // Generated by CodeDNA
250
+
251
+ {% if options.database === 'postgresql' %}
252
+ import { pgTable, serial, varchar, integer, boolean, timestamp, text, jsonb } from 'drizzle-orm/pg-core';
253
+ {% elif options.database === 'mysql' %}
254
+ import { mysqlTable, serial, varchar, int, boolean, timestamp, text, json } from 'drizzle-orm/mysql-core';
255
+ {% elif options.database === 'sqlite' %}
256
+ import { sqliteTable, integer as sqliteInt, text as sqliteText } from 'drizzle-orm/sqlite-core';
257
+ {% endif %}
258
+ import { relations } from 'drizzle-orm';
259
+
260
+ {% if options.database === 'postgresql' %}
261
+ export const {{ entity.name | lower }} = pgTable('{{ entity.name | lower | plural }}', {
262
+ {% elif options.database === 'mysql' %}
263
+ export const {{ entity.name | lower }} = mysqlTable('{{ entity.name | lower | plural }}', {
264
+ {% elif options.database === 'sqlite' %}
265
+ export const {{ entity.name | lower }} = sqliteTable('{{ entity.name | lower | plural }}', {
266
+ {% endif %}
267
+ id: serial('id').primaryKey(),
268
+ {% for field in entity.fields %}
269
+ {% if field.type.kind === 'primitive' %}
270
+ {{ field.name }}: {{ field.type | sqlType | lower }}('{{ field.name }}'){% if field | hasConstraint('required') %}.notNull(){% endif %}{% if field | hasConstraint('unique') %}.unique(){% endif %}{% if field | getConstraint('default') %}.default({{ field | getConstraint('default') }}){% endif %},
271
+ {% elif field.type.kind === 'reference' %}
272
+ {{ field.name }}Id: integer('{{ field.name }}_id'){% if field | hasConstraint('required') %}.notNull(){% endif %}.references(() => {{ field.type.entity | lower }}.id),
273
+ {% elif field.type.kind === 'enum' %}
274
+ {{ field.name }}: varchar('{{ field.name }}', { length: 50 }){% if field | hasConstraint('required') %}.notNull(){% endif %},
275
+ {% elif field.type.kind === 'array' %}
276
+ {{ field.name }}: {% if options.database === 'postgresql' %}jsonb{% else %}json{% endif %}('{{ field.name }}'){% if field | hasConstraint('required') %}.notNull(){% endif %},
277
+ {% elif field.type.kind === 'json' %}
278
+ {{ field.name }}: {% if options.database === 'postgresql' %}jsonb{% else %}json{% endif %}('{{ field.name }}'){% if field | hasConstraint('required') %}.notNull(){% endif %},
279
+ {% endif %}
280
+ {% endfor %}
281
+ createdAt: timestamp('created_at').defaultNow().notNull(),
282
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),
283
+ });
284
+
285
+ // Relations
286
+ export const {{ entity.name | lower }}Relations = relations({{ entity.name | lower }}, ({ one, many }) => ({
287
+ {% for field in entity.fields %}
288
+ {% if field.type.kind === 'reference' %}
289
+ {% if field.type.relation === 'oneToMany' %}
290
+ {{ field.name }}: one({{ field.type.entity | lower }}, {
291
+ fields: [{{ entity.name | lower }}.{{ field.name }}Id],
292
+ references: [{{ field.type.entity | lower }}.id],
293
+ }),
294
+ {% elif field.type.relation === 'manyToMany' %}
295
+ {{ field.name }}: many({{ field.type.entity | lower }}),
296
+ {% else %}
297
+ {{ field.name }}: one({{ field.type.entity | lower }}, {
298
+ fields: [{{ entity.name | lower }}.{{ field.name }}Id],
299
+ references: [{{ field.type.entity | lower }}.id],
300
+ }),
301
+ {% endif %}
302
+ {% endif %}
303
+ {% endfor %}
304
+ }));
305
+
306
+ // TypeScript type
307
+ export type {{ entity.name }} = typeof {{ entity.name | lower }}.$inferSelect;
308
+ export type New{{ entity.name }} = typeof {{ entity.name | lower }}.$inferInsert;
309
+ `;
310
+ }
311
+ getMigrationTemplate() {
312
+ return `-- {{ entity.name }} Migration
313
+ -- Generated by CodeDNA
314
+
315
+ CREATE TABLE {{ entity.name | lower | plural }} (
316
+ id SERIAL PRIMARY KEY,
317
+ {% for field in entity.fields %}
318
+ {% if field.type.kind === 'primitive' %}
319
+ {{ field.name }} {{ field.type | sqlType }}{% if field | hasConstraint('required') %} NOT NULL{% endif %}{% if field | hasConstraint('unique') %} UNIQUE{% endif %},
320
+ {% elif field.type.kind === 'reference' %}
321
+ {{ field.name }}_id INTEGER{% if field | hasConstraint('required') %} NOT NULL{% endif %} REFERENCES {{ field.type.entity | lower | plural }}(id),
322
+ {% elif field.type.kind === 'enum' %}
323
+ {{ field.name }} VARCHAR(50){% if field | hasConstraint('required') %} NOT NULL{% endif %},
324
+ {% elif field.type.kind === 'array' or field.type.kind === 'json' %}
325
+ {{ field.name }} {% if options.database === 'postgresql' %}JSONB{% else %}JSON{% endif %}{% if field | hasConstraint('required') %} NOT NULL{% endif %},
326
+ {% endif %}
327
+ {% endfor %}
328
+ created_at TIMESTAMP NOT NULL DEFAULT NOW(),
329
+ updated_at TIMESTAMP NOT NULL DEFAULT NOW()
330
+ );
331
+
332
+ -- Indexes
333
+ {% for field in entity.fields %}
334
+ {% if field | hasConstraint('index') %}
335
+ CREATE INDEX idx_{{ entity.name | lower }}_{{ field.name }} ON {{ entity.name | lower | plural }}({{ field.name }});
336
+ {% endif %}
337
+ {% if field.type.kind === 'reference' %}
338
+ CREATE INDEX idx_{{ entity.name | lower }}_{{ field.name }}_id ON {{ entity.name | lower | plural }}({{ field.name }}_id);
339
+ {% endif %}
340
+ {% endfor %}
341
+ `;
342
+ }
343
+ getDbClientTemplate() {
344
+ return `// Database Client Configuration
345
+ // Generated by CodeDNA
346
+
347
+ {% if options.database === 'postgresql' %}
348
+ import { drizzle } from 'drizzle-orm/postgres-js';
349
+ import postgres from 'postgres';
350
+ {% elif options.database === 'mysql' %}
351
+ import { drizzle } from 'drizzle-orm/mysql2';
352
+ import mysql from 'mysql2/promise';
353
+ {% elif options.database === 'sqlite' %}
354
+ import { drizzle } from 'drizzle-orm/better-sqlite3';
355
+ import Database from 'better-sqlite3';
356
+ {% endif %}
357
+
358
+ import * as schema from './schema';
359
+
360
+ {% if options.deployment === 'cloudflare' %}
361
+ // Cloudflare D1 binding (set in wrangler.toml)
362
+ declare const DB: D1Database;
363
+
364
+ export const db = drizzle(DB, { schema });
365
+ {% else %}
366
+ // Database connection
367
+ const connectionString = process.env.DATABASE_URL!;
368
+
369
+ {% if options.database === 'postgresql' %}
370
+ const queryClient = postgres(connectionString);
371
+ export const db = drizzle(queryClient, { schema });
372
+ {% elif options.database === 'mysql' %}
373
+ const pool = mysql.createPool(connectionString);
374
+ export const db = drizzle(pool, { schema });
375
+ {% elif options.database === 'sqlite' %}
376
+ const sqlite = new Database(connectionString);
377
+ export const db = drizzle(sqlite, { schema });
378
+ {% endif %}
379
+ {% endif %}
380
+ `;
381
+ }
382
+ getQueriesTemplate() {
383
+ return `// {{ entity.name }} Queries
384
+ // Generated by CodeDNA
385
+
386
+ import { db } from '../db/client';
387
+ import { {{ entity.name | lower }} } from '../db/schema/{{ entity.name | lower }}';
388
+ import { eq, desc } from 'drizzle-orm';
389
+
390
+ /**
391
+ * Get all {{ entity.name | plural }}
392
+ */
393
+ export async function getAll{{ entity.name | plural }}() {
394
+ return db.select().from({{ entity.name | lower }}).orderBy(desc({{ entity.name | lower }}.createdAt));
395
+ }
396
+
397
+ /**
398
+ * Get {{ entity.name }} by ID
399
+ */
400
+ export async function get{{ entity.name }}ById(id: number) {
401
+ const result = await db.select().from({{ entity.name | lower }}).where(eq({{ entity.name | lower }}.id, id));
402
+ return result[0] || null;
403
+ }
404
+
405
+ /**
406
+ * Search {{ entity.name | plural }}
407
+ */
408
+ export async function search{{ entity.name | plural }}(query: string) {
409
+ // Implement search logic based on your needs
410
+ return db.select().from({{ entity.name | lower }});
411
+ }
412
+ `;
413
+ }
414
+ getMutationsTemplate() {
415
+ return `// {{ entity.name }} Mutations (Server Actions)
416
+ // Generated by CodeDNA
417
+
418
+ 'use server';
419
+
420
+ import { db } from '../db/client';
421
+ import { {{ entity.name | lower }}, New{{ entity.name }} } from '../db/schema/{{ entity.name | lower }}';
422
+ import { eq } from 'drizzle-orm';
423
+ import { revalidatePath } from '@tanstack/react-router';
424
+
425
+ /**
426
+ * Create new {{ entity.name }}
427
+ */
428
+ export async function create{{ entity.name }}(data: New{{ entity.name }}) {
429
+ const result = await db.insert({{ entity.name | lower }}).values(data).returning();
430
+ revalidatePath('/{{ entity.name | lower }}');
431
+ return result[0];
432
+ }
433
+
434
+ /**
435
+ * Update {{ entity.name }}
436
+ */
437
+ export async function update{{ entity.name }}(id: number, data: Partial<New{{ entity.name }}>) {
438
+ const result = await db
439
+ .update({{ entity.name | lower }})
440
+ .set({ ...data, updatedAt: new Date() })
441
+ .where(eq({{ entity.name | lower }}.id, id))
442
+ .returning();
443
+
444
+ revalidatePath('/{{ entity.name | lower }}');
445
+ revalidatePath(\`/{{ entity.name | lower }}/\${id}\`);
446
+ return result[0];
447
+ }
448
+
449
+ /**
450
+ * Delete {{ entity.name }}
451
+ */
452
+ export async function delete{{ entity.name }}(id: number) {
453
+ await db.delete({{ entity.name | lower }}).where(eq({{ entity.name | lower }}.id, id));
454
+ revalidatePath('/{{ entity.name | lower }}');
455
+ }
456
+ `;
457
+ }
458
+ getIndexRouteTemplate() {
459
+ return `// {{ entity.name }} List Route
460
+ // Generated by CodeDNA
461
+
462
+ import { createFileRoute } from '@tanstack/react-router';
463
+ import { getAll{{ entity.name | plural }} } from '../../queries/{{ entity.name | lower }}';
464
+ import { {{ entity.name }}List } from '../../components/{{ entity.name }}List';
465
+
466
+ export const Route = createFileRoute('/{{ entity.name | lower }}/')({
467
+ loader: async () => {
468
+ const items = await getAll{{ entity.name | plural }}();
469
+ return { items };
470
+ },
471
+ component: {{ entity.name }}IndexPage,
472
+ });
473
+
474
+ function {{ entity.name }}IndexPage() {
475
+ const { items } = Route.useLoaderData();
476
+
477
+ return (
478
+ <div className="container mx-auto p-6">
479
+ <div className="flex justify-between items-center mb-6">
480
+ <h1 className="text-3xl font-bold">{{ entity.name | plural }}</h1>
481
+ <a
482
+ href="/{{ entity.name | lower }}/create"
483
+ className="btn btn-primary"
484
+ >
485
+ Create {{ entity.name }}
486
+ </a>
487
+ </div>
488
+ <{{ entity.name }}List items={items} />
489
+ </div>
490
+ );
491
+ }
492
+ `;
493
+ }
494
+ getDetailRouteTemplate() {
495
+ return `// {{ entity.name }} Detail Route
496
+ // Generated by CodeDNA
497
+
498
+ import { createFileRoute } from '@tanstack/react-router';
499
+ import { get{{ entity.name }}ById } from '../../queries/{{ entity.name | lower }}';
500
+ import { notFound } from '@tanstack/react-router';
501
+
502
+ export const Route = createFileRoute('/{{ entity.name | lower }}/$id')({
503
+ loader: async ({ params }) => {
504
+ const item = await get{{ entity.name }}ById(Number(params.id));
505
+ if (!item) throw notFound();
506
+ return { item };
507
+ },
508
+ component: {{ entity.name }}DetailPage,
509
+ });
510
+
511
+ function {{ entity.name }}DetailPage() {
512
+ const { item } = Route.useLoaderData();
513
+
514
+ return (
515
+ <div className="container mx-auto p-6">
516
+ <h1 className="text-3xl font-bold mb-6">{{ entity.name }} Details</h1>
517
+ <div className="card">
518
+ {% for field in entity.fields %}
519
+ <div className="mb-4">
520
+ <label className="font-semibold">{{ field.name | capitalize }}:</label>
521
+ <p>{item.{{ field.name }}}</p>
522
+ </div>
523
+ {% endfor %}
524
+ </div>
525
+ <div className="mt-6 flex gap-4">
526
+ <a href="/{{ entity.name | lower }}/{item.id}/edit" className="btn btn-secondary">
527
+ Edit
528
+ </a>
529
+ <a href="/{{ entity.name | lower }}" className="btn">
530
+ Back to List
531
+ </a>
532
+ </div>
533
+ </div>
534
+ );
535
+ }
536
+ `;
537
+ }
538
+ getCreateRouteTemplate() {
539
+ return `// {{ entity.name }} Create Route
540
+ // Generated by CodeDNA
541
+
542
+ import { createFileRoute, useNavigate } from '@tanstack/react-router';
543
+ import { {{ entity.name }}Form } from '../../components/{{ entity.name }}Form';
544
+ import { create{{ entity.name }} } from '../../mutations/{{ entity.name | lower }}';
545
+
546
+ export const Route = createFileRoute('/{{ entity.name | lower }}/create')({
547
+ component: {{ entity.name }}CreatePage,
548
+ });
549
+
550
+ function {{ entity.name }}CreatePage() {
551
+ const navigate = useNavigate();
552
+
553
+ const handleSubmit = async (data: any) => {
554
+ const created = await create{{ entity.name }}(data);
555
+ navigate({ to: '/{{ entity.name | lower }}/$id', params: { id: created.id.toString() } });
556
+ };
557
+
558
+ return (
559
+ <div className="container mx-auto p-6">
560
+ <h1 className="text-3xl font-bold mb-6">Create {{ entity.name }}</h1>
561
+ <{{ entity.name }}Form onSubmit={handleSubmit} />
562
+ </div>
563
+ );
564
+ }
565
+ `;
566
+ }
567
+ getEditRouteTemplate() {
568
+ return `// {{ entity.name }} Edit Route
569
+ // Generated by CodeDNA
570
+
571
+ import { createFileRoute, useNavigate } from '@tanstack/react-router';
572
+ import { get{{ entity.name }}ById } from '../../../queries/{{ entity.name | lower }}';
573
+ import { update{{ entity.name }} } from '../../../mutations/{{ entity.name | lower }}';
574
+ import { {{ entity.name }}Form } from '../../../components/{{ entity.name }}Form';
575
+ import { notFound } from '@tanstack/react-router';
576
+
577
+ export const Route = createFileRoute('/{{ entity.name | lower }}/$id/edit')({
578
+ loader: async ({ params }) => {
579
+ const item = await get{{ entity.name }}ById(Number(params.id));
580
+ if (!item) throw notFound();
581
+ return { item };
582
+ },
583
+ component: {{ entity.name }}EditPage,
584
+ });
585
+
586
+ function {{ entity.name }}EditPage() {
587
+ const { item } = Route.useLoaderData();
588
+ const navigate = useNavigate();
589
+
590
+ const handleSubmit = async (data: any) => {
591
+ await update{{ entity.name }}(item.id, data);
592
+ navigate({ to: '/{{ entity.name | lower }}/$id', params: { id: item.id.toString() } });
593
+ };
594
+
595
+ return (
596
+ <div className="container mx-auto p-6">
597
+ <h1 className="text-3xl font-bold mb-6">Edit {{ entity.name }}</h1>
598
+ <{{ entity.name }}Form initialData={item} onSubmit={handleSubmit} />
599
+ </div>
600
+ );
601
+ }
602
+ `;
603
+ }
604
+ getListComponentTemplate() {
605
+ return `// {{ entity.name }} List Component
606
+ // Generated by CodeDNA
607
+
608
+ import { {{ entity.name }} } from '../types/{{ entity.name | lower }}';
609
+
610
+ interface {{ entity.name }}ListProps {
611
+ items: {{ entity.name }}[];
612
+ }
613
+
614
+ export function {{ entity.name }}List({ items }: {{ entity.name }}ListProps) {
615
+ return (
616
+ <div className="overflow-x-auto">
617
+ <table className="table w-full">
618
+ <thead>
619
+ <tr>
620
+ <th>ID</th>
621
+ {% for field in entity.fields %}
622
+ <th>{{ field.name | capitalize }}</th>
623
+ {% endfor %}
624
+ <th>Actions</th>
625
+ </tr>
626
+ </thead>
627
+ <tbody>
628
+ {items.map((item) => (
629
+ <tr key={item.id}>
630
+ <td>{item.id}</td>
631
+ {% for field in entity.fields %}
632
+ <td>{item.{{ field.name }}}</td>
633
+ {% endfor %}
634
+ <td>
635
+ <a href={\`/{{ entity.name | lower }}/\${item.id}\`} className="btn btn-sm">
636
+ View
637
+ </a>
638
+ </td>
639
+ </tr>
640
+ ))}
641
+ </tbody>
642
+ </table>
643
+ </div>
644
+ );
645
+ }
646
+ `;
647
+ }
648
+ getFormComponentTemplate() {
649
+ return `// {{ entity.name }} Form Component
650
+ // Generated by CodeDNA
651
+
652
+ import { useState } from 'react';
653
+ import { {{ entity.name }} } from '../types/{{ entity.name | lower }}';
654
+
655
+ interface {{ entity.name }}FormProps {
656
+ initialData?: Partial<{{ entity.name }}>;
657
+ onSubmit: (data: any) => Promise<void>;
658
+ }
659
+
660
+ export function {{ entity.name }}Form({ initialData, onSubmit }: {{ entity.name }}FormProps) {
661
+ const [formData, setFormData] = useState(initialData || {});
662
+ const [isSubmitting, setIsSubmitting] = useState(false);
663
+
664
+ const handleSubmit = async (e: React.FormEvent) => {
665
+ e.preventDefault();
666
+ setIsSubmitting(true);
667
+ try {
668
+ await onSubmit(formData);
669
+ } finally {
670
+ setIsSubmitting(false);
671
+ }
672
+ };
673
+
674
+ return (
675
+ <form onSubmit={handleSubmit} className="space-y-4">
676
+ {% for field in entity.fields %}
677
+ {% if field.type.kind === 'primitive' %}
678
+ <div>
679
+ <label className="label">{{ field.name | capitalize }}</label>
680
+ <input
681
+ type="{% if field.type.value === 'email' %}email{% elif field.type.value === 'url' %}url{% elif field.type.value === 'integer' or field.type.value === 'decimal' %}number{% else %}text{% endif %}"
682
+ className="input w-full"
683
+ value={formData.{{ field.name }} || ''}
684
+ onChange={(e) => setFormData({ ...formData, {{ field.name }}: e.target.value })}
685
+ {% if field | hasConstraint('required') %}required{% endif %}
686
+ />
687
+ </div>
688
+ {% elif field.type.kind === 'enum' %}
689
+ <div>
690
+ <label className="label">{{ field.name | capitalize }}</label>
691
+ <select
692
+ className="select w-full"
693
+ value={formData.{{ field.name }} || ''}
694
+ onChange={(e) => setFormData({ ...formData, {{ field.name }}: e.target.value })}
695
+ {% if field | hasConstraint('required') %}required{% endif %}
696
+ >
697
+ <option value="">Select {{ field.name }}</option>
698
+ {% for value in field.type.values %}
699
+ <option value="{{ value }}">{{ value | capitalize }}</option>
700
+ {% endfor %}
701
+ </select>
702
+ </div>
703
+ {% endif %}
704
+ {% endfor %}
705
+
706
+ <div className="flex gap-4">
707
+ <button type="submit" className="btn btn-primary" disabled={isSubmitting}>
708
+ {isSubmitting ? 'Saving...' : 'Save'}
709
+ </button>
710
+ <a href="/{{ entity.name | lower }}" className="btn">
711
+ Cancel
712
+ </a>
713
+ </div>
714
+ </form>
715
+ );
716
+ }
717
+ `;
718
+ }
719
+ getTypesTemplate() {
720
+ return `// {{ entity.name }} Types
721
+ // Generated by CodeDNA
722
+
723
+ export interface {{ entity.name }} {
724
+ id: number;
725
+ {% for field in entity.fields %}
726
+ {{ field.name }}: {{ field.type | tsType }}{% if not (field | hasConstraint('required')) %} | null{% endif %};
727
+ {% endfor %}
728
+ createdAt: Date;
729
+ updatedAt: Date;
730
+ }
731
+
732
+ export type New{{ entity.name }} = Omit<{{ entity.name }}, 'id' | 'createdAt' | 'updatedAt'>;
733
+ `;
734
+ }
735
+ getWranglerConfigTemplate() {
736
+ return `# Wrangler Configuration for Cloudflare
737
+ # Generated by CodeDNA
738
+
739
+ name = "{{ options.projectName || 'tanstack-app' }}"
740
+ main = "src/index.ts"
741
+ compatibility_date = "2024-12-01"
742
+
743
+ [[ d1_databases ]]
744
+ binding = "DB"
745
+ database_name = "{{ options.database || 'app' }}"
746
+ database_id = "{{ options.databaseId || 'YOUR_DATABASE_ID' }}"
747
+
748
+ [[ kv_namespaces ]]
749
+ binding = "KV"
750
+ id = "{{ options.kvId || 'YOUR_KV_ID' }}"
751
+ `;
752
+ }
753
+ getDrizzleConfigTemplate() {
754
+ return `// Drizzle Configuration
755
+ // Generated by CodeDNA
756
+
757
+ import type { Config } from 'drizzle-kit';
758
+
759
+ export default {
760
+ schema: './src/db/schema',
761
+ out: './drizzle/migrations',
762
+ {% if options.database === 'postgresql' %}
763
+ driver: 'pg',
764
+ {% elif options.database === 'mysql' %}
765
+ driver: 'mysql2',
766
+ {% elif options.database === 'sqlite' %}
767
+ driver: 'better-sqlite',
768
+ {% endif %}
769
+ dbCredentials: {
770
+ {% if options.database === 'postgresql' %}
771
+ connectionString: process.env.DATABASE_URL!,
772
+ {% elif options.database === 'mysql' %}
773
+ connectionString: process.env.DATABASE_URL!,
774
+ {% elif options.database === 'sqlite' %}
775
+ url: process.env.DATABASE_URL!,
776
+ {% endif %}
777
+ },
778
+ } satisfies Config;
779
+ `;
780
+ }
781
+ getPackageJsonTemplate() {
782
+ return `{
783
+ "name": "{{ options.projectName || 'tanstack-drizzle-app' }}",
784
+ "version": "0.1.0",
785
+ "private": true,
786
+ "type": "module",
787
+ "scripts": {
788
+ "dev": "vinxi dev",
789
+ "build": "vinxi build",
790
+ "start": "vinxi start",
791
+ "db:generate": "drizzle-kit generate",
792
+ "db:migrate": "drizzle-kit migrate",
793
+ "db:push": "drizzle-kit push",
794
+ "db:studio": "drizzle-kit studio"
795
+ },
796
+ "dependencies": {
797
+ "@tanstack/react-router": "^1.80.0",
798
+ "@tanstack/start": "^1.80.0",
799
+ "react": "^19.0.0",
800
+ "react-dom": "^19.0.0",
801
+ {% if options.database === 'postgresql' %}
802
+ "drizzle-orm": "^0.38.0",
803
+ "postgres": "^3.4.5",
804
+ {% elif options.database === 'mysql' %}
805
+ "drizzle-orm": "^0.38.0",
806
+ "mysql2": "^3.11.5",
807
+ {% elif options.database === 'sqlite' %}
808
+ "drizzle-orm": "^0.38.0",
809
+ "better-sqlite3": "^11.8.1",
810
+ {% endif %}
811
+ "vinxi": "^0.4.0"
812
+ },
813
+ "devDependencies": {
814
+ "@types/node": "^22.10.2",
815
+ "@types/react": "^19.0.0",
816
+ "@types/react-dom": "^19.0.0",
817
+ "drizzle-kit": "^0.29.0",
818
+ "typescript": "^5.7.2",
819
+ "vite": "^6.0.0"
820
+ }
821
+ }
822
+ `;
823
+ }
824
+ }