archetype-engine 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +241 -0
- package/dist/src/ai/adapters/anthropic.d.ts +31 -0
- package/dist/src/ai/adapters/anthropic.d.ts.map +1 -0
- package/dist/src/ai/adapters/anthropic.js +75 -0
- package/dist/src/ai/adapters/openai.d.ts +33 -0
- package/dist/src/ai/adapters/openai.d.ts.map +1 -0
- package/dist/src/ai/adapters/openai.js +120 -0
- package/dist/src/ai/adapters/vercel.d.ts +434 -0
- package/dist/src/ai/adapters/vercel.d.ts.map +1 -0
- package/dist/src/ai/adapters/vercel.js +162 -0
- package/dist/src/ai/index.d.ts +492 -0
- package/dist/src/ai/index.d.ts.map +1 -0
- package/dist/src/ai/index.js +71 -0
- package/dist/src/ai/state.d.ts +13 -0
- package/dist/src/ai/state.d.ts.map +1 -0
- package/dist/src/ai/state.js +215 -0
- package/dist/src/ai/tools.d.ts +13 -0
- package/dist/src/ai/tools.d.ts.map +1 -0
- package/dist/src/ai/tools.js +257 -0
- package/dist/src/ai/types.d.ts +196 -0
- package/dist/src/ai/types.d.ts.map +1 -0
- package/dist/src/ai/types.js +9 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +540 -0
- package/dist/src/core/utils.d.ts +27 -0
- package/dist/src/core/utils.d.ts.map +1 -0
- package/dist/src/core/utils.js +56 -0
- package/dist/src/entity.d.ts +165 -0
- package/dist/src/entity.d.ts.map +1 -0
- package/dist/src/entity.js +108 -0
- package/dist/src/fields.d.ts +207 -0
- package/dist/src/fields.d.ts.map +1 -0
- package/dist/src/fields.js +291 -0
- package/dist/src/generators/erd-ir.d.ts +10 -0
- package/dist/src/generators/erd-ir.d.ts.map +1 -0
- package/dist/src/generators/erd-ir.js +119 -0
- package/dist/src/index.d.ts +51 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +101 -0
- package/dist/src/init/dependencies.d.ts +31 -0
- package/dist/src/init/dependencies.d.ts.map +1 -0
- package/dist/src/init/dependencies.js +101 -0
- package/dist/src/init/entity-templates.d.ts +42 -0
- package/dist/src/init/entity-templates.d.ts.map +1 -0
- package/dist/src/init/entity-templates.js +367 -0
- package/dist/src/init/index.d.ts +10 -0
- package/dist/src/init/index.d.ts.map +1 -0
- package/dist/src/init/index.js +250 -0
- package/dist/src/init/prompts.d.ts +11 -0
- package/dist/src/init/prompts.d.ts.map +1 -0
- package/dist/src/init/prompts.js +275 -0
- package/dist/src/init/templates.d.ts +24 -0
- package/dist/src/init/templates.d.ts.map +1 -0
- package/dist/src/init/templates.js +587 -0
- package/dist/src/json/index.d.ts +11 -0
- package/dist/src/json/index.d.ts.map +1 -0
- package/dist/src/json/index.js +26 -0
- package/dist/src/json/parser.d.ts +61 -0
- package/dist/src/json/parser.d.ts.map +1 -0
- package/dist/src/json/parser.js +309 -0
- package/dist/src/json/types.d.ts +275 -0
- package/dist/src/json/types.d.ts.map +1 -0
- package/dist/src/json/types.js +10 -0
- package/dist/src/manifest.d.ts +147 -0
- package/dist/src/manifest.d.ts.map +1 -0
- package/dist/src/manifest.js +104 -0
- package/dist/src/relations.d.ts +96 -0
- package/dist/src/relations.d.ts.map +1 -0
- package/dist/src/relations.js +108 -0
- package/dist/src/source.d.ts +93 -0
- package/dist/src/source.d.ts.map +1 -0
- package/dist/src/source.js +89 -0
- package/dist/src/template/context.d.ts +34 -0
- package/dist/src/template/context.d.ts.map +1 -0
- package/dist/src/template/context.js +31 -0
- package/dist/src/template/index.d.ts +6 -0
- package/dist/src/template/index.d.ts.map +1 -0
- package/dist/src/template/index.js +12 -0
- package/dist/src/template/registry.d.ts +18 -0
- package/dist/src/template/registry.d.ts.map +1 -0
- package/dist/src/template/registry.js +89 -0
- package/dist/src/template/runner.d.ts +9 -0
- package/dist/src/template/runner.d.ts.map +1 -0
- package/dist/src/template/runner.js +125 -0
- package/dist/src/template/types.d.ts +73 -0
- package/dist/src/template/types.d.ts.map +1 -0
- package/dist/src/template/types.js +3 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/api.d.ts +22 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/api.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/api.js +866 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.d.ts +20 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/auth.js +273 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.d.ts +22 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/crud-hooks.js +237 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.d.ts +30 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/hooks.js +345 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.d.ts +25 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/i18n.js +199 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/index.d.ts +8 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/index.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/index.js +18 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.d.ts +22 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/schema.js +270 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/service.d.ts +23 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/service.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/service.js +304 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.d.ts +21 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/generators/validation.js +248 -0
- package/dist/src/templates/nextjs-drizzle-trpc/index.d.ts +30 -0
- package/dist/src/templates/nextjs-drizzle-trpc/index.d.ts.map +1 -0
- package/dist/src/templates/nextjs-drizzle-trpc/index.js +71 -0
- package/dist/src/validation/index.d.ts +71 -0
- package/dist/src/validation/index.d.ts.map +1 -0
- package/dist/src/validation/index.js +314 -0
- package/package.json +86 -0
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// File templates for archetype init
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.getConfigTemplate = getConfigTemplate;
|
|
5
|
+
exports.getTaskEntityTemplate = getTaskEntityTemplate;
|
|
6
|
+
exports.getProductEntityTemplate = getProductEntityTemplate;
|
|
7
|
+
exports.getDbTemplate = getDbTemplate;
|
|
8
|
+
exports.getTrpcServerTemplate = getTrpcServerTemplate;
|
|
9
|
+
exports.getTrpcClientTemplate = getTrpcClientTemplate;
|
|
10
|
+
exports.getProvidersTemplate = getProvidersTemplate;
|
|
11
|
+
exports.getApiRouteTemplate = getApiRouteTemplate;
|
|
12
|
+
exports.getDrizzleConfigTemplate = getDrizzleConfigTemplate;
|
|
13
|
+
exports.getAuthTemplate = getAuthTemplate;
|
|
14
|
+
exports.getAuthRouteTemplate = getAuthRouteTemplate;
|
|
15
|
+
exports.getEnvExampleTemplate = getEnvExampleTemplate;
|
|
16
|
+
exports.getGitignoreTemplate = getGitignoreTemplate;
|
|
17
|
+
exports.getAllTemplateFiles = getAllTemplateFiles;
|
|
18
|
+
exports.getPackageJsonScripts = getPackageJsonScripts;
|
|
19
|
+
const entity_templates_1 = require("./entity-templates");
|
|
20
|
+
// archetype.config.ts
|
|
21
|
+
function getConfigTemplate(config) {
|
|
22
|
+
// Headless mode config
|
|
23
|
+
if (config.mode === 'headless') {
|
|
24
|
+
const authConfig = config.auth && config.authProviders
|
|
25
|
+
? `
|
|
26
|
+
auth: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
providers: ${JSON.stringify(config.authProviders)},
|
|
29
|
+
},`
|
|
30
|
+
: '';
|
|
31
|
+
const i18nConfig = config.i18n
|
|
32
|
+
? `
|
|
33
|
+
i18n: {
|
|
34
|
+
languages: ${JSON.stringify(config.i18n)},
|
|
35
|
+
defaultLanguage: '${config.i18n[0]}',
|
|
36
|
+
},`
|
|
37
|
+
: '';
|
|
38
|
+
const entityImport = config.includeExamples
|
|
39
|
+
? `import { Product } from './archetype/entities/product'`
|
|
40
|
+
: '';
|
|
41
|
+
const entities = config.includeExamples ? '[Product]' : '[]';
|
|
42
|
+
const sourceUrl = config.externalApiUrl || 'env:API_URL';
|
|
43
|
+
return `import { defineConfig, external } from 'archetype-engine'
|
|
44
|
+
${entityImport}
|
|
45
|
+
|
|
46
|
+
export default defineConfig({
|
|
47
|
+
template: '${config.template}',
|
|
48
|
+
mode: 'headless',
|
|
49
|
+
source: external('${sourceUrl}'),
|
|
50
|
+
entities: ${entities},${authConfig}${i18nConfig}
|
|
51
|
+
})
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
// Full mode config (with database)
|
|
55
|
+
const dbConfig = config.database === 'sqlite'
|
|
56
|
+
? `{
|
|
57
|
+
type: 'sqlite',
|
|
58
|
+
file: './sqlite.db',
|
|
59
|
+
}`
|
|
60
|
+
: config.database === 'postgres'
|
|
61
|
+
? `{
|
|
62
|
+
type: 'postgres',
|
|
63
|
+
url: process.env.DATABASE_URL!,
|
|
64
|
+
}`
|
|
65
|
+
: `{
|
|
66
|
+
type: 'mysql',
|
|
67
|
+
url: process.env.DATABASE_URL!,
|
|
68
|
+
}`;
|
|
69
|
+
const authConfig = config.auth && config.authProviders
|
|
70
|
+
? `
|
|
71
|
+
auth: {
|
|
72
|
+
enabled: true,
|
|
73
|
+
providers: ${JSON.stringify(config.authProviders)},
|
|
74
|
+
},`
|
|
75
|
+
: '';
|
|
76
|
+
const i18nConfig = config.i18n
|
|
77
|
+
? `
|
|
78
|
+
i18n: {
|
|
79
|
+
languages: ${JSON.stringify(config.i18n)},
|
|
80
|
+
defaultLanguage: '${config.i18n[0]}',
|
|
81
|
+
},`
|
|
82
|
+
: '';
|
|
83
|
+
let entityImport = '';
|
|
84
|
+
let entities = '[]';
|
|
85
|
+
if (config.includeExamples) {
|
|
86
|
+
if (config.entityTemplate && config.entityTemplate !== 'simple') {
|
|
87
|
+
const template = (0, entity_templates_1.getEntityTemplate)(config.entityTemplate);
|
|
88
|
+
if (template) {
|
|
89
|
+
// Import all entities from the template
|
|
90
|
+
const imports = template.entities.map(e => {
|
|
91
|
+
const entityName = e.filename.replace('.ts', '').split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join('');
|
|
92
|
+
return `import { ${entityName} } from './archetype/entities/${e.filename.replace('.ts', '')}'`;
|
|
93
|
+
});
|
|
94
|
+
entityImport = imports.join('\n');
|
|
95
|
+
const entityNames = template.entities.map(e => {
|
|
96
|
+
return e.filename.replace('.ts', '').split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join('');
|
|
97
|
+
});
|
|
98
|
+
entities = `[${entityNames.join(', ')}]`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
entityImport = `import { Task } from './archetype/entities/task'`;
|
|
103
|
+
entities = '[Task]';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return `import { defineConfig } from 'archetype-engine'
|
|
107
|
+
${entityImport}
|
|
108
|
+
|
|
109
|
+
export default defineConfig({
|
|
110
|
+
template: '${config.template}',
|
|
111
|
+
entities: ${entities},
|
|
112
|
+
database: ${dbConfig},${authConfig}${i18nConfig}
|
|
113
|
+
})
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
// archetype/entities/task.ts (example entity for full mode)
|
|
117
|
+
function getTaskEntityTemplate() {
|
|
118
|
+
return `import { defineEntity, text, boolean, date } from 'archetype-engine'
|
|
119
|
+
|
|
120
|
+
export const Task = defineEntity('Task', {
|
|
121
|
+
fields: {
|
|
122
|
+
title: text().required().min(1).max(200).label('Title'),
|
|
123
|
+
description: text().optional().max(2000).label('Description'),
|
|
124
|
+
completed: boolean().default(false).label('Completed'),
|
|
125
|
+
dueDate: date().optional().label('Due Date'),
|
|
126
|
+
},
|
|
127
|
+
behaviors: {
|
|
128
|
+
timestamps: true,
|
|
129
|
+
},
|
|
130
|
+
})
|
|
131
|
+
`;
|
|
132
|
+
}
|
|
133
|
+
// archetype/entities/product.ts (example entity for headless mode)
|
|
134
|
+
function getProductEntityTemplate() {
|
|
135
|
+
return `import { defineEntity, text, number } from 'archetype-engine'
|
|
136
|
+
|
|
137
|
+
// Example entity for headless mode - uses external API
|
|
138
|
+
// The source is inherited from the config's global source
|
|
139
|
+
export const Product = defineEntity('Product', {
|
|
140
|
+
fields: {
|
|
141
|
+
sku: text().required().label('SKU'),
|
|
142
|
+
name: text().required().min(1).max(200).label('Name'),
|
|
143
|
+
description: text().optional().max(2000).label('Description'),
|
|
144
|
+
price: number().required().positive().label('Price'),
|
|
145
|
+
stock: number().optional().integer().min(0).label('Stock'),
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
`;
|
|
149
|
+
}
|
|
150
|
+
// src/server/db.ts
|
|
151
|
+
function getDbTemplate(database) {
|
|
152
|
+
switch (database) {
|
|
153
|
+
case 'sqlite':
|
|
154
|
+
return `import { drizzle } from 'drizzle-orm/better-sqlite3'
|
|
155
|
+
import Database from 'better-sqlite3'
|
|
156
|
+
import * as schema from '@/generated/db/schema'
|
|
157
|
+
|
|
158
|
+
const sqlite = new Database('sqlite.db')
|
|
159
|
+
export const db = drizzle(sqlite, { schema })
|
|
160
|
+
`;
|
|
161
|
+
case 'postgres':
|
|
162
|
+
return `import { drizzle } from 'drizzle-orm/postgres-js'
|
|
163
|
+
import postgres from 'postgres'
|
|
164
|
+
import * as schema from '@/generated/db/schema'
|
|
165
|
+
|
|
166
|
+
const client = postgres(process.env.DATABASE_URL!)
|
|
167
|
+
export const db = drizzle(client, { schema })
|
|
168
|
+
`;
|
|
169
|
+
case 'mysql':
|
|
170
|
+
return `import { drizzle } from 'drizzle-orm/mysql2'
|
|
171
|
+
import mysql from 'mysql2/promise'
|
|
172
|
+
import * as schema from '@/generated/db/schema'
|
|
173
|
+
|
|
174
|
+
const connection = await mysql.createConnection(process.env.DATABASE_URL!)
|
|
175
|
+
export const db = drizzle(connection, { schema, mode: 'default' })
|
|
176
|
+
`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// src/server/trpc.ts
|
|
180
|
+
function getTrpcServerTemplate(config) {
|
|
181
|
+
// Headless mode (no database)
|
|
182
|
+
if (config.mode === 'headless') {
|
|
183
|
+
if (config.auth) {
|
|
184
|
+
return `import { initTRPC, TRPCError } from '@trpc/server'
|
|
185
|
+
import { auth } from './auth'
|
|
186
|
+
|
|
187
|
+
interface Context {
|
|
188
|
+
session: Awaited<ReturnType<typeof auth>> | null
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export async function createContext(): Promise<Context> {
|
|
192
|
+
const session = await auth()
|
|
193
|
+
return { session }
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const t = initTRPC.context<Context>().create()
|
|
197
|
+
|
|
198
|
+
export const router = t.router
|
|
199
|
+
export const publicProcedure = t.procedure
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Protected procedure - requires authentication
|
|
203
|
+
* Use for entity operations that need auth
|
|
204
|
+
*/
|
|
205
|
+
export const protectedProcedure = t.procedure.use(async ({ ctx, next }) => {
|
|
206
|
+
if (!ctx.session?.user) {
|
|
207
|
+
throw new TRPCError({ code: 'UNAUTHORIZED', message: 'You must be logged in' })
|
|
208
|
+
}
|
|
209
|
+
return next({
|
|
210
|
+
ctx: {
|
|
211
|
+
...ctx,
|
|
212
|
+
session: ctx.session,
|
|
213
|
+
user: ctx.session.user,
|
|
214
|
+
},
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
`;
|
|
218
|
+
}
|
|
219
|
+
return `import { initTRPC } from '@trpc/server'
|
|
220
|
+
|
|
221
|
+
const t = initTRPC.create()
|
|
222
|
+
|
|
223
|
+
export const router = t.router
|
|
224
|
+
export const publicProcedure = t.procedure
|
|
225
|
+
`;
|
|
226
|
+
}
|
|
227
|
+
// Full mode (with database)
|
|
228
|
+
if (config.auth) {
|
|
229
|
+
return `import { initTRPC, TRPCError } from '@trpc/server'
|
|
230
|
+
import { auth } from './auth'
|
|
231
|
+
import { db } from './db'
|
|
232
|
+
|
|
233
|
+
interface Context {
|
|
234
|
+
session: Awaited<ReturnType<typeof auth>> | null
|
|
235
|
+
db: typeof db
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export async function createContext(): Promise<Context> {
|
|
239
|
+
const session = await auth()
|
|
240
|
+
return { session, db }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const t = initTRPC.context<Context>().create()
|
|
244
|
+
|
|
245
|
+
export const router = t.router
|
|
246
|
+
export const publicProcedure = t.procedure
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Protected procedure - requires authentication
|
|
250
|
+
* Use for entity operations that need auth
|
|
251
|
+
*/
|
|
252
|
+
export const protectedProcedure = t.procedure.use(async ({ ctx, next }) => {
|
|
253
|
+
if (!ctx.session?.user) {
|
|
254
|
+
throw new TRPCError({ code: 'UNAUTHORIZED', message: 'You must be logged in' })
|
|
255
|
+
}
|
|
256
|
+
return next({
|
|
257
|
+
ctx: {
|
|
258
|
+
...ctx,
|
|
259
|
+
session: ctx.session,
|
|
260
|
+
user: ctx.session.user,
|
|
261
|
+
},
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
`;
|
|
265
|
+
}
|
|
266
|
+
return `import { initTRPC } from '@trpc/server'
|
|
267
|
+
import { db } from './db'
|
|
268
|
+
|
|
269
|
+
interface Context {
|
|
270
|
+
db: typeof db
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export function createContext(): Context {
|
|
274
|
+
return { db }
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const t = initTRPC.context<Context>().create()
|
|
278
|
+
|
|
279
|
+
export const router = t.router
|
|
280
|
+
export const publicProcedure = t.procedure
|
|
281
|
+
`;
|
|
282
|
+
}
|
|
283
|
+
// src/lib/trpc.ts
|
|
284
|
+
function getTrpcClientTemplate() {
|
|
285
|
+
return `import { createTRPCReact } from '@trpc/react-query'
|
|
286
|
+
import type { AppRouter } from '@/generated/trpc/routers'
|
|
287
|
+
|
|
288
|
+
export const trpc = createTRPCReact<AppRouter>()
|
|
289
|
+
`;
|
|
290
|
+
}
|
|
291
|
+
// src/app/providers.tsx
|
|
292
|
+
function getProvidersTemplate() {
|
|
293
|
+
return `'use client'
|
|
294
|
+
|
|
295
|
+
import { useState } from 'react'
|
|
296
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
297
|
+
import { httpBatchLink } from '@trpc/client'
|
|
298
|
+
import { trpc } from '@/lib/trpc'
|
|
299
|
+
|
|
300
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
301
|
+
const [queryClient] = useState(() => new QueryClient())
|
|
302
|
+
const [trpcClient] = useState(() =>
|
|
303
|
+
trpc.createClient({
|
|
304
|
+
links: [httpBatchLink({ url: '/api/trpc' })],
|
|
305
|
+
})
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
<trpc.Provider client={trpcClient} queryClient={queryClient}>
|
|
310
|
+
<QueryClientProvider client={queryClient}>
|
|
311
|
+
{children}
|
|
312
|
+
</QueryClientProvider>
|
|
313
|
+
</trpc.Provider>
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
`;
|
|
317
|
+
}
|
|
318
|
+
// src/app/api/trpc/[trpc]/route.ts
|
|
319
|
+
function getApiRouteTemplate(config) {
|
|
320
|
+
if (config.auth) {
|
|
321
|
+
return `import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
|
|
322
|
+
import { appRouter } from '@/generated/trpc/routers'
|
|
323
|
+
import { createContext } from '@/server/trpc'
|
|
324
|
+
|
|
325
|
+
const handler = (req: Request) =>
|
|
326
|
+
fetchRequestHandler({
|
|
327
|
+
endpoint: '/api/trpc',
|
|
328
|
+
req,
|
|
329
|
+
router: appRouter,
|
|
330
|
+
createContext,
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
export { handler as GET, handler as POST }
|
|
334
|
+
`;
|
|
335
|
+
}
|
|
336
|
+
return `import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
|
|
337
|
+
import { appRouter } from '@/generated/trpc/routers'
|
|
338
|
+
import { createContext } from '@/server/trpc'
|
|
339
|
+
|
|
340
|
+
const handler = (req: Request) =>
|
|
341
|
+
fetchRequestHandler({
|
|
342
|
+
endpoint: '/api/trpc',
|
|
343
|
+
req,
|
|
344
|
+
router: appRouter,
|
|
345
|
+
createContext,
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
export { handler as GET, handler as POST }
|
|
349
|
+
`;
|
|
350
|
+
}
|
|
351
|
+
// drizzle.config.ts
|
|
352
|
+
function getDrizzleConfigTemplate(database) {
|
|
353
|
+
const dialectMap = {
|
|
354
|
+
sqlite: 'sqlite',
|
|
355
|
+
postgres: 'postgresql',
|
|
356
|
+
mysql: 'mysql',
|
|
357
|
+
};
|
|
358
|
+
const credentialsMap = {
|
|
359
|
+
sqlite: "url: 'sqlite.db'",
|
|
360
|
+
postgres: 'url: process.env.DATABASE_URL!',
|
|
361
|
+
mysql: 'url: process.env.DATABASE_URL!',
|
|
362
|
+
};
|
|
363
|
+
return `import { defineConfig } from 'drizzle-kit'
|
|
364
|
+
|
|
365
|
+
export default defineConfig({
|
|
366
|
+
schema: ['./generated/db/schema.ts', './generated/db/auth-schema.ts'],
|
|
367
|
+
out: './drizzle',
|
|
368
|
+
dialect: '${dialectMap[database]}',
|
|
369
|
+
dbCredentials: { ${credentialsMap[database]} },
|
|
370
|
+
})
|
|
371
|
+
`;
|
|
372
|
+
}
|
|
373
|
+
// src/server/auth.ts - NextAuth configuration
|
|
374
|
+
function getAuthTemplate(config) {
|
|
375
|
+
const providers = config.authProviders || ['credentials'];
|
|
376
|
+
const imports = ['import NextAuth from "next-auth"'];
|
|
377
|
+
const providerSetups = [];
|
|
378
|
+
if (providers.includes('credentials')) {
|
|
379
|
+
imports.push('import Credentials from "next-auth/providers/credentials"');
|
|
380
|
+
providerSetups.push(` Credentials({
|
|
381
|
+
credentials: {
|
|
382
|
+
email: { label: "Email", type: "email" },
|
|
383
|
+
password: { label: "Password", type: "password" },
|
|
384
|
+
},
|
|
385
|
+
async authorize(credentials) {
|
|
386
|
+
// SCAFFOLD: Replace this placeholder with your authentication logic
|
|
387
|
+
// Example implementation:
|
|
388
|
+
// 1. Validate credentials exist
|
|
389
|
+
// 2. Look up user in database by email
|
|
390
|
+
// 3. Verify password with bcrypt
|
|
391
|
+
// 4. Return user object or null
|
|
392
|
+
if (!credentials?.email || !credentials?.password) return null
|
|
393
|
+
|
|
394
|
+
// Example: look up user in database
|
|
395
|
+
// const user = await db.query.users.findFirst({
|
|
396
|
+
// where: eq(users.email, credentials.email)
|
|
397
|
+
// })
|
|
398
|
+
// if (!user || !await bcrypt.compare(credentials.password, user.password)) {
|
|
399
|
+
// return null
|
|
400
|
+
// }
|
|
401
|
+
// return { id: user.id, email: user.email, name: user.name }
|
|
402
|
+
|
|
403
|
+
return null
|
|
404
|
+
},
|
|
405
|
+
})`);
|
|
406
|
+
}
|
|
407
|
+
if (providers.includes('google')) {
|
|
408
|
+
imports.push('import Google from "next-auth/providers/google"');
|
|
409
|
+
providerSetups.push(' Google');
|
|
410
|
+
}
|
|
411
|
+
if (providers.includes('github')) {
|
|
412
|
+
imports.push('import GitHub from "next-auth/providers/github"');
|
|
413
|
+
providerSetups.push(' GitHub');
|
|
414
|
+
}
|
|
415
|
+
if (providers.includes('discord')) {
|
|
416
|
+
imports.push('import Discord from "next-auth/providers/discord"');
|
|
417
|
+
providerSetups.push(' Discord');
|
|
418
|
+
}
|
|
419
|
+
return `${imports.join('\n')}
|
|
420
|
+
import { DrizzleAdapter } from "@auth/drizzle-adapter"
|
|
421
|
+
import { db } from "./db"
|
|
422
|
+
import * as authSchema from "@/generated/db/auth-schema"
|
|
423
|
+
|
|
424
|
+
export const { handlers, auth, signIn, signOut } = NextAuth({
|
|
425
|
+
adapter: DrizzleAdapter(db, {
|
|
426
|
+
usersTable: authSchema.users,
|
|
427
|
+
accountsTable: authSchema.accounts,
|
|
428
|
+
sessionsTable: authSchema.sessions,
|
|
429
|
+
verificationTokensTable: authSchema.verificationTokens,
|
|
430
|
+
}),
|
|
431
|
+
session: { strategy: "jwt" },
|
|
432
|
+
providers: [
|
|
433
|
+
${providerSetups.join(',\n')},
|
|
434
|
+
],
|
|
435
|
+
callbacks: {
|
|
436
|
+
session: ({ session, token }) => ({
|
|
437
|
+
...session,
|
|
438
|
+
user: {
|
|
439
|
+
...session.user,
|
|
440
|
+
id: token.sub,
|
|
441
|
+
},
|
|
442
|
+
}),
|
|
443
|
+
},
|
|
444
|
+
})
|
|
445
|
+
`;
|
|
446
|
+
}
|
|
447
|
+
// src/app/api/auth/[...nextauth]/route.ts
|
|
448
|
+
function getAuthRouteTemplate() {
|
|
449
|
+
return `import { handlers } from "@/server/auth"
|
|
450
|
+
|
|
451
|
+
export const { GET, POST } = handlers
|
|
452
|
+
`;
|
|
453
|
+
}
|
|
454
|
+
// .env.example
|
|
455
|
+
function getEnvExampleTemplate(config) {
|
|
456
|
+
const lines = ['# Authentication'];
|
|
457
|
+
lines.push('AUTH_SECRET=your-auth-secret-here # Generate with: npx auth secret');
|
|
458
|
+
const providers = config.authProviders || [];
|
|
459
|
+
if (providers.includes('google')) {
|
|
460
|
+
lines.push('');
|
|
461
|
+
lines.push('# Google OAuth');
|
|
462
|
+
lines.push('AUTH_GOOGLE_ID=your-google-client-id');
|
|
463
|
+
lines.push('AUTH_GOOGLE_SECRET=your-google-client-secret');
|
|
464
|
+
}
|
|
465
|
+
if (providers.includes('github')) {
|
|
466
|
+
lines.push('');
|
|
467
|
+
lines.push('# GitHub OAuth');
|
|
468
|
+
lines.push('AUTH_GITHUB_ID=your-github-client-id');
|
|
469
|
+
lines.push('AUTH_GITHUB_SECRET=your-github-client-secret');
|
|
470
|
+
}
|
|
471
|
+
if (providers.includes('discord')) {
|
|
472
|
+
lines.push('');
|
|
473
|
+
lines.push('# Discord OAuth');
|
|
474
|
+
lines.push('AUTH_DISCORD_ID=your-discord-client-id');
|
|
475
|
+
lines.push('AUTH_DISCORD_SECRET=your-discord-client-secret');
|
|
476
|
+
}
|
|
477
|
+
if (config.database && config.database !== 'sqlite') {
|
|
478
|
+
lines.push('');
|
|
479
|
+
lines.push('# Database');
|
|
480
|
+
lines.push('DATABASE_URL=your-database-url');
|
|
481
|
+
}
|
|
482
|
+
return lines.join('\n') + '\n';
|
|
483
|
+
}
|
|
484
|
+
// .gitignore for Archetype projects
|
|
485
|
+
function getGitignoreTemplate() {
|
|
486
|
+
return `# Generated by Archetype
|
|
487
|
+
generated/
|
|
488
|
+
|
|
489
|
+
# Dependencies
|
|
490
|
+
node_modules/
|
|
491
|
+
|
|
492
|
+
# Database
|
|
493
|
+
*.db
|
|
494
|
+
*.db-shm
|
|
495
|
+
*.db-wal
|
|
496
|
+
drizzle/
|
|
497
|
+
|
|
498
|
+
# Environment
|
|
499
|
+
.env
|
|
500
|
+
.env.local
|
|
501
|
+
.env*.local
|
|
502
|
+
|
|
503
|
+
# Next.js
|
|
504
|
+
.next/
|
|
505
|
+
out/
|
|
506
|
+
build/
|
|
507
|
+
dist/
|
|
508
|
+
|
|
509
|
+
# Misc
|
|
510
|
+
.DS_Store
|
|
511
|
+
*.log
|
|
512
|
+
.turbo
|
|
513
|
+
`;
|
|
514
|
+
}
|
|
515
|
+
function getAllTemplateFiles(config, structure) {
|
|
516
|
+
const prefix = structure.useSrcDir ? 'src/' : '';
|
|
517
|
+
const files = [
|
|
518
|
+
// Config - always needed
|
|
519
|
+
{ path: 'archetype.config.ts', content: getConfigTemplate(config) },
|
|
520
|
+
// Gitignore - always needed
|
|
521
|
+
{ path: '.gitignore', content: getGitignoreTemplate() },
|
|
522
|
+
];
|
|
523
|
+
if (config.mode === 'headless') {
|
|
524
|
+
// Headless mode: tRPC but no database
|
|
525
|
+
files.push({ path: `${prefix}server/trpc.ts`, content: getTrpcServerTemplate(config) }, { path: `${prefix}lib/trpc.ts`, content: getTrpcClientTemplate() }, { path: `${prefix}app/providers.tsx`, content: getProvidersTemplate() }, { path: `${prefix}app/api/trpc/[trpc]/route.ts`, content: getApiRouteTemplate(config) });
|
|
526
|
+
// Example entity for headless mode
|
|
527
|
+
if (config.includeExamples) {
|
|
528
|
+
if (config.entityTemplate && config.entityTemplate !== 'simple') {
|
|
529
|
+
// Use advanced template
|
|
530
|
+
const template = (0, entity_templates_1.getEntityTemplate)(config.entityTemplate);
|
|
531
|
+
if (template) {
|
|
532
|
+
template.entities.forEach(entity => {
|
|
533
|
+
files.push({ path: `archetype/entities/${entity.filename}`, content: entity.code });
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
// Use simple product example
|
|
539
|
+
files.push({ path: 'archetype/entities/product.ts', content: getProductEntityTemplate() });
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
// Auth files for headless mode (if auth enabled)
|
|
543
|
+
if (config.auth) {
|
|
544
|
+
files.push({ path: `${prefix}server/auth.ts`, content: getAuthTemplate(config) }, { path: `${prefix}app/api/auth/[...nextauth]/route.ts`, content: getAuthRouteTemplate() }, { path: '.env.example', content: getEnvExampleTemplate(config) });
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
// Full mode: database + tRPC
|
|
549
|
+
// database is guaranteed to be defined in full mode
|
|
550
|
+
const db = config.database;
|
|
551
|
+
files.push({ path: 'drizzle.config.ts', content: getDrizzleConfigTemplate(db) }, { path: `${prefix}server/db.ts`, content: getDbTemplate(db) }, { path: `${prefix}server/trpc.ts`, content: getTrpcServerTemplate(config) }, { path: `${prefix}lib/trpc.ts`, content: getTrpcClientTemplate() }, { path: `${prefix}app/providers.tsx`, content: getProvidersTemplate() }, { path: `${prefix}app/api/trpc/[trpc]/route.ts`, content: getApiRouteTemplate(config) });
|
|
552
|
+
// Example entities for full mode
|
|
553
|
+
if (config.includeExamples) {
|
|
554
|
+
if (config.entityTemplate && config.entityTemplate !== 'simple') {
|
|
555
|
+
// Use advanced template
|
|
556
|
+
const template = (0, entity_templates_1.getEntityTemplate)(config.entityTemplate);
|
|
557
|
+
if (template) {
|
|
558
|
+
template.entities.forEach(entity => {
|
|
559
|
+
files.push({ path: `archetype/entities/${entity.filename}`, content: entity.code });
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
// Use simple task example
|
|
565
|
+
files.push({ path: 'archetype/entities/task.ts', content: getTaskEntityTemplate() });
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
// Auth files for full mode (if auth enabled)
|
|
569
|
+
if (config.auth) {
|
|
570
|
+
files.push({ path: `${prefix}server/auth.ts`, content: getAuthTemplate(config) }, { path: `${prefix}app/api/auth/[...nextauth]/route.ts`, content: getAuthRouteTemplate() }, { path: '.env.example', content: getEnvExampleTemplate(config) });
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return files;
|
|
574
|
+
}
|
|
575
|
+
// package.json scripts to add
|
|
576
|
+
function getPackageJsonScripts(config) {
|
|
577
|
+
const scripts = {
|
|
578
|
+
'archetype:generate': 'archetype generate',
|
|
579
|
+
'archetype:view': 'archetype view',
|
|
580
|
+
};
|
|
581
|
+
// Only add database scripts for full mode
|
|
582
|
+
if (config.mode === 'full') {
|
|
583
|
+
scripts['db:push'] = 'drizzle-kit push';
|
|
584
|
+
scripts['db:studio'] = 'drizzle-kit studio';
|
|
585
|
+
}
|
|
586
|
+
return scripts;
|
|
587
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Input Module
|
|
3
|
+
*
|
|
4
|
+
* Provides types and parsers for AI agents to generate manifests using JSON
|
|
5
|
+
* instead of TypeScript code.
|
|
6
|
+
*
|
|
7
|
+
* @module json
|
|
8
|
+
*/
|
|
9
|
+
export * from './types';
|
|
10
|
+
export * from './parser';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/json/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JSON Input Module
|
|
4
|
+
*
|
|
5
|
+
* Provides types and parsers for AI agents to generate manifests using JSON
|
|
6
|
+
* instead of TypeScript code.
|
|
7
|
+
*
|
|
8
|
+
* @module json
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
22
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
__exportStar(require("./types"), exports);
|
|
26
|
+
__exportStar(require("./parser"), exports);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Parser - converts JSON manifest to IR
|
|
3
|
+
*
|
|
4
|
+
* @module json/parser
|
|
5
|
+
*/
|
|
6
|
+
import { FieldConfig } from '../fields';
|
|
7
|
+
import { RelationConfig } from '../relations';
|
|
8
|
+
import { EntityIR, ProtectedIR, HooksIR } from '../entity';
|
|
9
|
+
import { ManifestIR } from '../manifest';
|
|
10
|
+
import { ExternalSourceConfig } from '../source';
|
|
11
|
+
import { FieldJSON, RelationJSON, EntityJSON, ManifestJSON, ExternalSourceJSON, ProtectedJSON, HooksJSON } from './types';
|
|
12
|
+
/**
|
|
13
|
+
* Parse a JSON field definition to FieldConfig
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseFieldJSON(field: FieldJSON): FieldConfig;
|
|
16
|
+
/**
|
|
17
|
+
* Parse a JSON relation definition to RelationConfig
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseRelationJSON(relation: RelationJSON): RelationConfig;
|
|
20
|
+
/**
|
|
21
|
+
* Parse a JSON external source to ExternalSourceConfig
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseExternalSourceJSON(source: ExternalSourceJSON): ExternalSourceConfig;
|
|
24
|
+
/**
|
|
25
|
+
* Parse a JSON protected option to ProtectedIR
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseProtectedJSON(option?: ProtectedJSON): ProtectedIR;
|
|
28
|
+
/**
|
|
29
|
+
* Parse a JSON hooks option to HooksIR
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseHooksJSON(option?: boolean | HooksJSON): HooksIR;
|
|
32
|
+
/**
|
|
33
|
+
* Parse a JSON entity definition to EntityIR
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseEntityJSON(entity: EntityJSON): EntityIR;
|
|
36
|
+
/**
|
|
37
|
+
* Parse a JSON manifest to ManifestIR
|
|
38
|
+
*
|
|
39
|
+
* @param json - JSON manifest object or string
|
|
40
|
+
* @returns Compiled ManifestIR
|
|
41
|
+
* @throws Error if JSON is invalid or validation fails
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const manifest = parseManifestJSON({
|
|
46
|
+
* entities: [
|
|
47
|
+
* { name: 'User', fields: { email: { type: 'text', email: true } } }
|
|
48
|
+
* ],
|
|
49
|
+
* database: { type: 'sqlite', file: './app.db' }
|
|
50
|
+
* })
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseManifestJSON(json: ManifestJSON | string): ManifestIR;
|
|
54
|
+
/**
|
|
55
|
+
* Load manifest from a JSON file
|
|
56
|
+
*
|
|
57
|
+
* @param filePath - Path to JSON file
|
|
58
|
+
* @returns Compiled ManifestIR
|
|
59
|
+
*/
|
|
60
|
+
export declare function loadManifestFromJSONFile(filePath: string): Promise<ManifestIR>;
|
|
61
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +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,CAsC5D;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"}
|