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.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +241 -0
  3. package/dist/src/ai/adapters/anthropic.d.ts +31 -0
  4. package/dist/src/ai/adapters/anthropic.d.ts.map +1 -0
  5. package/dist/src/ai/adapters/anthropic.js +75 -0
  6. package/dist/src/ai/adapters/openai.d.ts +33 -0
  7. package/dist/src/ai/adapters/openai.d.ts.map +1 -0
  8. package/dist/src/ai/adapters/openai.js +120 -0
  9. package/dist/src/ai/adapters/vercel.d.ts +434 -0
  10. package/dist/src/ai/adapters/vercel.d.ts.map +1 -0
  11. package/dist/src/ai/adapters/vercel.js +162 -0
  12. package/dist/src/ai/index.d.ts +492 -0
  13. package/dist/src/ai/index.d.ts.map +1 -0
  14. package/dist/src/ai/index.js +71 -0
  15. package/dist/src/ai/state.d.ts +13 -0
  16. package/dist/src/ai/state.d.ts.map +1 -0
  17. package/dist/src/ai/state.js +215 -0
  18. package/dist/src/ai/tools.d.ts +13 -0
  19. package/dist/src/ai/tools.d.ts.map +1 -0
  20. package/dist/src/ai/tools.js +257 -0
  21. package/dist/src/ai/types.d.ts +196 -0
  22. package/dist/src/ai/types.d.ts.map +1 -0
  23. package/dist/src/ai/types.js +9 -0
  24. package/dist/src/cli.d.ts +3 -0
  25. package/dist/src/cli.d.ts.map +1 -0
  26. package/dist/src/cli.js +540 -0
  27. package/dist/src/core/utils.d.ts +27 -0
  28. package/dist/src/core/utils.d.ts.map +1 -0
  29. package/dist/src/core/utils.js +56 -0
  30. package/dist/src/entity.d.ts +165 -0
  31. package/dist/src/entity.d.ts.map +1 -0
  32. package/dist/src/entity.js +108 -0
  33. package/dist/src/fields.d.ts +207 -0
  34. package/dist/src/fields.d.ts.map +1 -0
  35. package/dist/src/fields.js +291 -0
  36. package/dist/src/generators/erd-ir.d.ts +10 -0
  37. package/dist/src/generators/erd-ir.d.ts.map +1 -0
  38. package/dist/src/generators/erd-ir.js +119 -0
  39. package/dist/src/index.d.ts +51 -0
  40. package/dist/src/index.d.ts.map +1 -0
  41. package/dist/src/index.js +101 -0
  42. package/dist/src/init/dependencies.d.ts +31 -0
  43. package/dist/src/init/dependencies.d.ts.map +1 -0
  44. package/dist/src/init/dependencies.js +101 -0
  45. package/dist/src/init/entity-templates.d.ts +42 -0
  46. package/dist/src/init/entity-templates.d.ts.map +1 -0
  47. package/dist/src/init/entity-templates.js +367 -0
  48. package/dist/src/init/index.d.ts +10 -0
  49. package/dist/src/init/index.d.ts.map +1 -0
  50. package/dist/src/init/index.js +250 -0
  51. package/dist/src/init/prompts.d.ts +11 -0
  52. package/dist/src/init/prompts.d.ts.map +1 -0
  53. package/dist/src/init/prompts.js +275 -0
  54. package/dist/src/init/templates.d.ts +24 -0
  55. package/dist/src/init/templates.d.ts.map +1 -0
  56. package/dist/src/init/templates.js +587 -0
  57. package/dist/src/json/index.d.ts +11 -0
  58. package/dist/src/json/index.d.ts.map +1 -0
  59. package/dist/src/json/index.js +26 -0
  60. package/dist/src/json/parser.d.ts +61 -0
  61. package/dist/src/json/parser.d.ts.map +1 -0
  62. package/dist/src/json/parser.js +309 -0
  63. package/dist/src/json/types.d.ts +275 -0
  64. package/dist/src/json/types.d.ts.map +1 -0
  65. package/dist/src/json/types.js +10 -0
  66. package/dist/src/manifest.d.ts +147 -0
  67. package/dist/src/manifest.d.ts.map +1 -0
  68. package/dist/src/manifest.js +104 -0
  69. package/dist/src/relations.d.ts +96 -0
  70. package/dist/src/relations.d.ts.map +1 -0
  71. package/dist/src/relations.js +108 -0
  72. package/dist/src/source.d.ts +93 -0
  73. package/dist/src/source.d.ts.map +1 -0
  74. package/dist/src/source.js +89 -0
  75. package/dist/src/template/context.d.ts +34 -0
  76. package/dist/src/template/context.d.ts.map +1 -0
  77. package/dist/src/template/context.js +31 -0
  78. package/dist/src/template/index.d.ts +6 -0
  79. package/dist/src/template/index.d.ts.map +1 -0
  80. package/dist/src/template/index.js +12 -0
  81. package/dist/src/template/registry.d.ts +18 -0
  82. package/dist/src/template/registry.d.ts.map +1 -0
  83. package/dist/src/template/registry.js +89 -0
  84. package/dist/src/template/runner.d.ts +9 -0
  85. package/dist/src/template/runner.d.ts.map +1 -0
  86. package/dist/src/template/runner.js +125 -0
  87. package/dist/src/template/types.d.ts +73 -0
  88. package/dist/src/template/types.d.ts.map +1 -0
  89. package/dist/src/template/types.js +3 -0
  90. package/dist/src/templates/nextjs-drizzle-trpc/generators/api.d.ts +22 -0
  91. package/dist/src/templates/nextjs-drizzle-trpc/generators/api.d.ts.map +1 -0
  92. package/dist/src/templates/nextjs-drizzle-trpc/generators/api.js +866 -0
  93. package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.d.ts +20 -0
  94. package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.d.ts.map +1 -0
  95. package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.js +273 -0
  96. package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.d.ts +22 -0
  97. package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.d.ts.map +1 -0
  98. package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.js +237 -0
  99. package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.d.ts +30 -0
  100. package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.d.ts.map +1 -0
  101. package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.js +345 -0
  102. package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.d.ts +25 -0
  103. package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.d.ts.map +1 -0
  104. package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.js +199 -0
  105. package/dist/src/templates/nextjs-drizzle-trpc/generators/index.d.ts +8 -0
  106. package/dist/src/templates/nextjs-drizzle-trpc/generators/index.d.ts.map +1 -0
  107. package/dist/src/templates/nextjs-drizzle-trpc/generators/index.js +18 -0
  108. package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.d.ts +22 -0
  109. package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.d.ts.map +1 -0
  110. package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.js +270 -0
  111. package/dist/src/templates/nextjs-drizzle-trpc/generators/service.d.ts +23 -0
  112. package/dist/src/templates/nextjs-drizzle-trpc/generators/service.d.ts.map +1 -0
  113. package/dist/src/templates/nextjs-drizzle-trpc/generators/service.js +304 -0
  114. package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.d.ts +21 -0
  115. package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.d.ts.map +1 -0
  116. package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.js +248 -0
  117. package/dist/src/templates/nextjs-drizzle-trpc/index.d.ts +30 -0
  118. package/dist/src/templates/nextjs-drizzle-trpc/index.d.ts.map +1 -0
  119. package/dist/src/templates/nextjs-drizzle-trpc/index.js +71 -0
  120. package/dist/src/validation/index.d.ts +71 -0
  121. package/dist/src/validation/index.d.ts.map +1 -0
  122. package/dist/src/validation/index.js +314 -0
  123. package/package.json +86 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Auth.js (next-auth v5) Schema Generator
3
+ *
4
+ * Generates database schema for Auth.js/NextAuth.js authentication tables.
5
+ * Only runs when auth.enabled is true in the manifest.
6
+ *
7
+ * Generated files:
8
+ * - db/auth-schema.ts - Auth tables (users, accounts, sessions, verificationTokens)
9
+ *
10
+ * Features:
11
+ * - Supports SQLite, PostgreSQL, and MySQL databases
12
+ * - Uses official Auth.js/Drizzle adapter schema format
13
+ * - Includes proper foreign key references with cascade delete
14
+ * - Uses composite primary keys for accounts and verification tokens
15
+ *
16
+ * @module generators/auth
17
+ */
18
+ import type { Generator } from '../../../template/types';
19
+ export declare const authGenerator: Generator;
20
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../../src/templates/nextjs-drizzle-trpc/generators/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,yBAAyB,CAAA;AAuOvE,eAAO,MAAM,aAAa,EAAE,SA4B3B,CAAA"}
@@ -0,0 +1,273 @@
1
+ "use strict";
2
+ /**
3
+ * Auth.js (next-auth v5) Schema Generator
4
+ *
5
+ * Generates database schema for Auth.js/NextAuth.js authentication tables.
6
+ * Only runs when auth.enabled is true in the manifest.
7
+ *
8
+ * Generated files:
9
+ * - db/auth-schema.ts - Auth tables (users, accounts, sessions, verificationTokens)
10
+ *
11
+ * Features:
12
+ * - Supports SQLite, PostgreSQL, and MySQL databases
13
+ * - Uses official Auth.js/Drizzle adapter schema format
14
+ * - Includes proper foreign key references with cascade delete
15
+ * - Uses composite primary keys for accounts and verification tokens
16
+ *
17
+ * @module generators/auth
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.authGenerator = void 0;
21
+ /**
22
+ * Generate SQLite-specific auth schema
23
+ *
24
+ * Uses sqliteTable with integer timestamps (timestamp_ms mode).
25
+ *
26
+ * @returns SQLite auth schema as string
27
+ */
28
+ function generateSqliteAuthSchema() {
29
+ return `// Auto-generated Auth.js schema for SQLite
30
+ // Do not edit manually - regenerate with: npx archetype generate
31
+
32
+ import {
33
+ integer,
34
+ sqliteTable,
35
+ text,
36
+ primaryKey,
37
+ } from 'drizzle-orm/sqlite-core'
38
+ import type { AdapterAccountType } from 'next-auth/adapters'
39
+
40
+ export const users = sqliteTable('user', {
41
+ id: text('id')
42
+ .primaryKey()
43
+ .$defaultFn(() => crypto.randomUUID()),
44
+ name: text('name'),
45
+ email: text('email').unique(),
46
+ emailVerified: integer('emailVerified', { mode: 'timestamp_ms' }),
47
+ image: text('image'),
48
+ })
49
+
50
+ export const accounts = sqliteTable(
51
+ 'account',
52
+ {
53
+ userId: text('userId')
54
+ .notNull()
55
+ .references(() => users.id, { onDelete: 'cascade' }),
56
+ type: text('type').$type<AdapterAccountType>().notNull(),
57
+ provider: text('provider').notNull(),
58
+ providerAccountId: text('providerAccountId').notNull(),
59
+ refresh_token: text('refresh_token'),
60
+ access_token: text('access_token'),
61
+ expires_at: integer('expires_at'),
62
+ token_type: text('token_type'),
63
+ scope: text('scope'),
64
+ id_token: text('id_token'),
65
+ session_state: text('session_state'),
66
+ },
67
+ (account) => ({
68
+ compoundKey: primaryKey({ columns: [account.provider, account.providerAccountId] }),
69
+ })
70
+ )
71
+
72
+ export const sessions = sqliteTable('session', {
73
+ sessionToken: text('sessionToken').primaryKey(),
74
+ userId: text('userId')
75
+ .notNull()
76
+ .references(() => users.id, { onDelete: 'cascade' }),
77
+ expires: integer('expires', { mode: 'timestamp_ms' }).notNull(),
78
+ })
79
+
80
+ export const verificationTokens = sqliteTable(
81
+ 'verificationToken',
82
+ {
83
+ identifier: text('identifier').notNull(),
84
+ token: text('token').notNull(),
85
+ expires: integer('expires', { mode: 'timestamp_ms' }).notNull(),
86
+ },
87
+ (verificationToken) => ({
88
+ compositePk: primaryKey({
89
+ columns: [verificationToken.identifier, verificationToken.token],
90
+ }),
91
+ })
92
+ )
93
+ `;
94
+ }
95
+ /**
96
+ * Generate PostgreSQL-specific auth schema
97
+ *
98
+ * Uses pgTable with native timestamp columns (date mode).
99
+ *
100
+ * @returns PostgreSQL auth schema as string
101
+ */
102
+ function generatePostgresAuthSchema() {
103
+ return `// Auto-generated Auth.js schema for PostgreSQL
104
+ // Do not edit manually - regenerate with: npx archetype generate
105
+
106
+ import {
107
+ integer,
108
+ pgTable,
109
+ primaryKey,
110
+ text,
111
+ timestamp,
112
+ } from 'drizzle-orm/pg-core'
113
+ import type { AdapterAccountType } from 'next-auth/adapters'
114
+
115
+ export const users = pgTable('user', {
116
+ id: text('id')
117
+ .primaryKey()
118
+ .$defaultFn(() => crypto.randomUUID()),
119
+ name: text('name'),
120
+ email: text('email').unique(),
121
+ emailVerified: timestamp('emailVerified', { mode: 'date' }),
122
+ image: text('image'),
123
+ })
124
+
125
+ export const accounts = pgTable(
126
+ 'account',
127
+ {
128
+ userId: text('userId')
129
+ .notNull()
130
+ .references(() => users.id, { onDelete: 'cascade' }),
131
+ type: text('type').$type<AdapterAccountType>().notNull(),
132
+ provider: text('provider').notNull(),
133
+ providerAccountId: text('providerAccountId').notNull(),
134
+ refresh_token: text('refresh_token'),
135
+ access_token: text('access_token'),
136
+ expires_at: integer('expires_at'),
137
+ token_type: text('token_type'),
138
+ scope: text('scope'),
139
+ id_token: text('id_token'),
140
+ session_state: text('session_state'),
141
+ },
142
+ (account) => ({
143
+ compoundKey: primaryKey({ columns: [account.provider, account.providerAccountId] }),
144
+ })
145
+ )
146
+
147
+ export const sessions = pgTable('session', {
148
+ sessionToken: text('sessionToken').primaryKey(),
149
+ userId: text('userId')
150
+ .notNull()
151
+ .references(() => users.id, { onDelete: 'cascade' }),
152
+ expires: timestamp('expires', { mode: 'date' }).notNull(),
153
+ })
154
+
155
+ export const verificationTokens = pgTable(
156
+ 'verificationToken',
157
+ {
158
+ identifier: text('identifier').notNull(),
159
+ token: text('token').notNull(),
160
+ expires: timestamp('expires', { mode: 'date' }).notNull(),
161
+ },
162
+ (verificationToken) => ({
163
+ compositePk: primaryKey({
164
+ columns: [verificationToken.identifier, verificationToken.token],
165
+ }),
166
+ })
167
+ )
168
+ `;
169
+ }
170
+ /**
171
+ * Generate MySQL-specific auth schema
172
+ *
173
+ * Uses mysqlTable with varchar fields (255 length) and timestamp columns.
174
+ *
175
+ * @returns MySQL auth schema as string
176
+ */
177
+ function generateMysqlAuthSchema() {
178
+ return `// Auto-generated Auth.js schema for MySQL
179
+ // Do not edit manually - regenerate with: npx archetype generate
180
+
181
+ import {
182
+ int,
183
+ mysqlTable,
184
+ primaryKey,
185
+ varchar,
186
+ timestamp,
187
+ } from 'drizzle-orm/mysql-core'
188
+ import type { AdapterAccountType } from 'next-auth/adapters'
189
+
190
+ export const users = mysqlTable('user', {
191
+ id: varchar('id', { length: 255 })
192
+ .primaryKey()
193
+ .$defaultFn(() => crypto.randomUUID()),
194
+ name: varchar('name', { length: 255 }),
195
+ email: varchar('email', { length: 255 }).unique(),
196
+ emailVerified: timestamp('emailVerified', { fsp: 3, mode: 'date' }),
197
+ image: varchar('image', { length: 255 }),
198
+ })
199
+
200
+ export const accounts = mysqlTable(
201
+ 'account',
202
+ {
203
+ userId: varchar('userId', { length: 255 })
204
+ .notNull()
205
+ .references(() => users.id, { onDelete: 'cascade' }),
206
+ type: varchar('type', { length: 255 }).$type<AdapterAccountType>().notNull(),
207
+ provider: varchar('provider', { length: 255 }).notNull(),
208
+ providerAccountId: varchar('providerAccountId', { length: 255 }).notNull(),
209
+ refresh_token: varchar('refresh_token', { length: 255 }),
210
+ access_token: varchar('access_token', { length: 255 }),
211
+ expires_at: int('expires_at'),
212
+ token_type: varchar('token_type', { length: 255 }),
213
+ scope: varchar('scope', { length: 255 }),
214
+ id_token: varchar('id_token', { length: 2048 }),
215
+ session_state: varchar('session_state', { length: 255 }),
216
+ },
217
+ (account) => ({
218
+ compoundKey: primaryKey({ columns: [account.provider, account.providerAccountId] }),
219
+ })
220
+ )
221
+
222
+ export const sessions = mysqlTable('session', {
223
+ sessionToken: varchar('sessionToken', { length: 255 }).primaryKey(),
224
+ userId: varchar('userId', { length: 255 })
225
+ .notNull()
226
+ .references(() => users.id, { onDelete: 'cascade' }),
227
+ expires: timestamp('expires', { mode: 'date' }).notNull(),
228
+ })
229
+
230
+ export const verificationTokens = mysqlTable(
231
+ 'verificationToken',
232
+ {
233
+ identifier: varchar('identifier', { length: 255 }).notNull(),
234
+ token: varchar('token', { length: 255 }).notNull(),
235
+ expires: timestamp('expires', { mode: 'date' }).notNull(),
236
+ },
237
+ (verificationToken) => ({
238
+ compositePk: primaryKey({
239
+ columns: [verificationToken.identifier, verificationToken.token],
240
+ }),
241
+ })
242
+ )
243
+ `;
244
+ }
245
+ exports.authGenerator = {
246
+ name: 'auth-schema',
247
+ description: 'Generate Auth.js schema for next-auth',
248
+ generate(manifest, ctx) {
249
+ // Skip if auth is not enabled
250
+ if (!manifest.auth.enabled) {
251
+ return [];
252
+ }
253
+ // Generate auth schema based on database type
254
+ let schemaContent;
255
+ if (ctx.database.isSqlite) {
256
+ schemaContent = generateSqliteAuthSchema();
257
+ }
258
+ else if (ctx.database.isPostgres) {
259
+ schemaContent = generatePostgresAuthSchema();
260
+ }
261
+ else if (ctx.database.isMysql) {
262
+ schemaContent = generateMysqlAuthSchema();
263
+ }
264
+ else {
265
+ // Default to SQLite for unknown
266
+ schemaContent = generateSqliteAuthSchema();
267
+ }
268
+ return [{
269
+ path: 'db/auth-schema.ts',
270
+ content: schemaContent,
271
+ }];
272
+ },
273
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * CRUD Hooks Generator
3
+ *
4
+ * Generates type-safe hook files for CRUD operations.
5
+ * Users implement hooks in these files to add custom business logic.
6
+ *
7
+ * Generated files:
8
+ * - hooks/types.ts - Type definitions for all hook signatures
9
+ * - hooks/{entity}.ts - Hook implementations (user-editable)
10
+ *
11
+ * Features:
12
+ * - Type-safe hook signatures with proper input/output types
13
+ * - beforeCreate/afterCreate hooks for create operations
14
+ * - beforeUpdate/afterUpdate hooks for update operations
15
+ * - beforeRemove/afterRemove hooks for delete operations
16
+ * - Hooks can modify input (before*) or perform side effects (after*)
17
+ *
18
+ * @module generators/crud-hooks
19
+ */
20
+ import type { Generator } from '../../../template/types';
21
+ export declare const crudHooksGenerator: Generator;
22
+ //# sourceMappingURL=crud-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crud-hooks.d.ts","sourceRoot":"","sources":["../../../../../src/templates/nextjs-drizzle-trpc/generators/crud-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,yBAAyB,CAAA;AAiNvE,eAAO,MAAM,kBAAkB,EAAE,SA8BhC,CAAA"}
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ /**
3
+ * CRUD Hooks Generator
4
+ *
5
+ * Generates type-safe hook files for CRUD operations.
6
+ * Users implement hooks in these files to add custom business logic.
7
+ *
8
+ * Generated files:
9
+ * - hooks/types.ts - Type definitions for all hook signatures
10
+ * - hooks/{entity}.ts - Hook implementations (user-editable)
11
+ *
12
+ * Features:
13
+ * - Type-safe hook signatures with proper input/output types
14
+ * - beforeCreate/afterCreate hooks for create operations
15
+ * - beforeUpdate/afterUpdate hooks for update operations
16
+ * - beforeRemove/afterRemove hooks for delete operations
17
+ * - Hooks can modify input (before*) or perform side effects (after*)
18
+ *
19
+ * @module generators/crud-hooks
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.crudHooksGenerator = void 0;
23
+ /**
24
+ * Check if entity has any hooks enabled
25
+ */
26
+ function hasAnyHooks(hooks) {
27
+ return Object.values(hooks).some(v => v);
28
+ }
29
+ /**
30
+ * Check if manifest has any entities with hooks
31
+ */
32
+ function manifestHasHooks(manifest) {
33
+ return manifest.entities.some(e => hasAnyHooks(e.hooks));
34
+ }
35
+ /**
36
+ * Generate the shared hooks types file
37
+ */
38
+ function generateHooksTypes(manifest) {
39
+ const entityTypes = [];
40
+ for (const entity of manifest.entities) {
41
+ if (!hasAnyHooks(entity.hooks))
42
+ continue;
43
+ const name = entity.name;
44
+ const hooks = entity.hooks;
45
+ // Build field types for CreateInput
46
+ const createFields = Object.entries(entity.fields)
47
+ .filter(([_, f]) => f.type !== 'computed')
48
+ .map(([fieldName, config]) => {
49
+ const optional = !config.required ? '?' : '';
50
+ let type = 'string';
51
+ if (config.type === 'number')
52
+ type = 'number';
53
+ if (config.type === 'boolean')
54
+ type = 'boolean';
55
+ if (config.type === 'enum' && config.enumValues) {
56
+ type = config.enumValues.map(v => `'${v}'`).join(' | ');
57
+ }
58
+ return ` ${fieldName}${optional}: ${type}`;
59
+ })
60
+ .join('\n');
61
+ // Build field types for UpdateInput (all optional)
62
+ const updateFields = Object.entries(entity.fields)
63
+ .filter(([_, f]) => f.type !== 'computed')
64
+ .map(([fieldName, config]) => {
65
+ let type = 'string';
66
+ if (config.type === 'number')
67
+ type = 'number';
68
+ if (config.type === 'boolean')
69
+ type = 'boolean';
70
+ if (config.type === 'enum' && config.enumValues) {
71
+ type = config.enumValues.map(v => `'${v}'`).join(' | ');
72
+ }
73
+ return ` ${fieldName}?: ${type}`;
74
+ })
75
+ .join('\n');
76
+ // Build hook interface members
77
+ const hookMembers = [];
78
+ if (hooks.beforeCreate) {
79
+ hookMembers.push(` /** Called before creating. Return modified input or throw to abort. */
80
+ beforeCreate?: (input: ${name}CreateInput, ctx: HookContext) => Promise<${name}CreateInput> | ${name}CreateInput`);
81
+ }
82
+ if (hooks.afterCreate) {
83
+ hookMembers.push(` /** Called after creation. For side effects like sending emails. */
84
+ afterCreate?: (record: ${name}Record, ctx: HookContext) => Promise<void> | void`);
85
+ }
86
+ if (hooks.beforeUpdate) {
87
+ hookMembers.push(` /** Called before updating. Return modified input or throw to abort. */
88
+ beforeUpdate?: (id: string, input: ${name}UpdateInput, ctx: HookContext) => Promise<${name}UpdateInput> | ${name}UpdateInput`);
89
+ }
90
+ if (hooks.afterUpdate) {
91
+ hookMembers.push(` /** Called after update. For side effects. */
92
+ afterUpdate?: (record: ${name}Record, ctx: HookContext) => Promise<void> | void`);
93
+ }
94
+ if (hooks.beforeRemove) {
95
+ hookMembers.push(` /** Called before removal. Throw to abort deletion. */
96
+ beforeRemove?: (id: string, ctx: HookContext) => Promise<void> | void`);
97
+ }
98
+ if (hooks.afterRemove) {
99
+ hookMembers.push(` /** Called after removal. For cleanup/archival. */
100
+ afterRemove?: (record: ${name}Record, ctx: HookContext) => Promise<void> | void`);
101
+ }
102
+ entityTypes.push(`
103
+ // ============ ${name} Hooks ============
104
+
105
+ export interface ${name}CreateInput {
106
+ ${createFields}
107
+ }
108
+
109
+ export interface ${name}UpdateInput {
110
+ ${updateFields}
111
+ }
112
+
113
+ export interface ${name}Record extends ${name}CreateInput {
114
+ id: string
115
+ createdAt: string
116
+ updatedAt: string
117
+ }
118
+
119
+ export interface ${name}Hooks {
120
+ ${hookMembers.join('\n')}
121
+ }`);
122
+ }
123
+ return `// Auto-generated hook types
124
+ // Do not edit manually - regenerate with: npx archetype generate
125
+
126
+ /**
127
+ * Hook context passed to all hooks
128
+ * Contains user session and other request context
129
+ */
130
+ export interface HookContext {
131
+ /** User session (if authenticated) */
132
+ user?: {
133
+ id: string
134
+ email?: string
135
+ name?: string
136
+ }
137
+ /** Request headers */
138
+ headers?: Record<string, string>
139
+ }
140
+ ${entityTypes.join('\n')}
141
+ `;
142
+ }
143
+ /**
144
+ * Generate a stub hooks file for an entity
145
+ */
146
+ function generateEntityHooks(entity) {
147
+ const name = entity.name;
148
+ const lowerName = name.toLowerCase();
149
+ const hooks = entity.hooks;
150
+ const imports = [`${name}Hooks`, 'HookContext'];
151
+ if (hooks.beforeCreate || hooks.afterCreate) {
152
+ imports.push(`${name}CreateInput`);
153
+ }
154
+ if (hooks.beforeUpdate) {
155
+ imports.push(`${name}UpdateInput`);
156
+ }
157
+ if (hooks.afterCreate || hooks.afterUpdate || hooks.afterRemove) {
158
+ imports.push(`${name}Record`);
159
+ }
160
+ const hookImplementations = [];
161
+ if (hooks.beforeCreate) {
162
+ hookImplementations.push(`
163
+ async beforeCreate(input, ctx) {
164
+ // Validate business rules or modify input
165
+ // throw new Error('message') to abort
166
+ return input
167
+ },`);
168
+ }
169
+ if (hooks.afterCreate) {
170
+ hookImplementations.push(`
171
+ async afterCreate(record, ctx) {
172
+ // Side effects: send email, audit log, sync external system
173
+ },`);
174
+ }
175
+ if (hooks.beforeUpdate) {
176
+ hookImplementations.push(`
177
+ async beforeUpdate(id, input, ctx) {
178
+ // Validate business rules or modify input
179
+ // throw new Error('message') to abort
180
+ return input
181
+ },`);
182
+ }
183
+ if (hooks.afterUpdate) {
184
+ hookImplementations.push(`
185
+ async afterUpdate(record, ctx) {
186
+ // Side effects: sync external system, invalidate cache
187
+ },`);
188
+ }
189
+ if (hooks.beforeRemove) {
190
+ hookImplementations.push(`
191
+ async beforeRemove(id, ctx) {
192
+ // Check if deletion is allowed
193
+ // throw new Error('message') to abort
194
+ },`);
195
+ }
196
+ if (hooks.afterRemove) {
197
+ hookImplementations.push(`
198
+ async afterRemove(record, ctx) {
199
+ // Cleanup: archive data, remove related records
200
+ },`);
201
+ }
202
+ return `// ${name} CRUD Hooks
203
+ // Implement your business logic here
204
+ // This file is user-managed - it won't be overwritten by regenerate
205
+
206
+ import type { ${imports.join(', ')} } from './types'
207
+
208
+ export const ${lowerName}Hooks: ${name}Hooks = {${hookImplementations.join('')}
209
+ }
210
+ `;
211
+ }
212
+ exports.crudHooksGenerator = {
213
+ name: 'crud-hooks',
214
+ description: 'Generate CRUD hook files',
215
+ generate(manifest, ctx) {
216
+ // Only generate if at least one entity has hooks
217
+ if (!manifestHasHooks(manifest)) {
218
+ return [];
219
+ }
220
+ const files = [];
221
+ // Generate shared types file
222
+ files.push({
223
+ path: 'hooks/types.ts',
224
+ content: generateHooksTypes(manifest),
225
+ });
226
+ // Generate hook implementation files for entities with hooks
227
+ for (const entity of manifest.entities) {
228
+ if (hasAnyHooks(entity.hooks)) {
229
+ files.push({
230
+ path: `hooks/${entity.name.toLowerCase()}.ts`,
231
+ content: generateEntityHooks(entity),
232
+ });
233
+ }
234
+ }
235
+ return files;
236
+ },
237
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * React Hooks Generator
3
+ *
4
+ * Generates React hooks for data fetching and form handling using tRPC and React Hook Form.
5
+ * Provides a complete set of hooks for each entity's CRUD operations.
6
+ *
7
+ * Generated files:
8
+ * - hooks/use{Entity}.ts - Hooks for list, get, create, edit, and remove operations
9
+ *
10
+ * Generated hooks per entity:
11
+ * - use{Entity}s() - List all entities (useQuery)
12
+ * - use{Entity}(id) - Get single entity by ID (useQuery)
13
+ * - use{Entity}Form() - Create form with validation and mutation
14
+ * - use{Entity}EditForm(id) - Edit form with data loading and mutation
15
+ * - use{Entity}Remove() - Delete mutation with cache invalidation
16
+ * - useCreate{Entity}() - Create mutation without form
17
+ * - useUpdate{Entity}() - Update mutation without form
18
+ *
19
+ * Features:
20
+ * - Zod validation integration via zodResolver
21
+ * - Automatic tRPC cache invalidation on mutations
22
+ * - i18n support for validation messages when multiple languages configured
23
+ * - Form reset on successful create
24
+ * - Null-to-undefined conversion for form compatibility
25
+ *
26
+ * @module generators/hooks
27
+ */
28
+ import type { Generator } from '../../../template/types';
29
+ export declare const hooksGenerator: Generator;
30
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../../../src/templates/nextjs-drizzle-trpc/generators/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,yBAAyB,CAAA;AAmUvE,eAAO,MAAM,cAAc,EAAE,SAU5B,CAAA"}