vonosan-cli 0.1.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/dist/__tests__/env-parity.pbt.test.d.ts +15 -0
- package/dist/__tests__/env-parity.pbt.test.d.ts.map +1 -0
- package/dist/__tests__/env-parity.pbt.test.js +125 -0
- package/dist/__tests__/env-parity.pbt.test.js.map +1 -0
- package/dist/__tests__/module-generator.pbt.test.d.ts +15 -0
- package/dist/__tests__/module-generator.pbt.test.d.ts.map +1 -0
- package/dist/__tests__/module-generator.pbt.test.js +130 -0
- package/dist/__tests__/module-generator.pbt.test.js.map +1 -0
- package/dist/commands/add.d.ts +21 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +128 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/audit.d.ts +18 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +73 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/branch-finish.d.ts +19 -0
- package/dist/commands/branch-finish.d.ts.map +1 -0
- package/dist/commands/branch-finish.js +80 -0
- package/dist/commands/branch-finish.js.map +1 -0
- package/dist/commands/branch-new.d.ts +17 -0
- package/dist/commands/branch-new.d.ts.map +1 -0
- package/dist/commands/branch-new.js +70 -0
- package/dist/commands/branch-new.js.map +1 -0
- package/dist/commands/commit.d.ts +21 -0
- package/dist/commands/commit.d.ts.map +1 -0
- package/dist/commands/commit.js +79 -0
- package/dist/commands/commit.js.map +1 -0
- package/dist/commands/db.d.ts +28 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +83 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/env-add.d.ts +17 -0
- package/dist/commands/env-add.d.ts.map +1 -0
- package/dist/commands/env-add.js +73 -0
- package/dist/commands/env-add.js.map +1 -0
- package/dist/commands/fix-headers.d.ts +15 -0
- package/dist/commands/fix-headers.d.ts.map +1 -0
- package/dist/commands/fix-headers.js +37 -0
- package/dist/commands/fix-headers.js.map +1 -0
- package/dist/commands/fix-logs.d.ts +15 -0
- package/dist/commands/fix-logs.d.ts.map +1 -0
- package/dist/commands/fix-logs.js +87 -0
- package/dist/commands/fix-logs.js.map +1 -0
- package/dist/commands/jobs.d.ts +17 -0
- package/dist/commands/jobs.d.ts.map +1 -0
- package/dist/commands/jobs.js +107 -0
- package/dist/commands/jobs.js.map +1 -0
- package/dist/commands/lint.d.ts +15 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +49 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/make.d.ts +31 -0
- package/dist/commands/make.d.ts.map +1 -0
- package/dist/commands/make.js +176 -0
- package/dist/commands/make.js.map +1 -0
- package/dist/commands/migrate.d.ts +43 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +120 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/schema-sync.d.ts +17 -0
- package/dist/commands/schema-sync.d.ts.map +1 -0
- package/dist/commands/schema-sync.js +48 -0
- package/dist/commands/schema-sync.js.map +1 -0
- package/dist/commands/test.d.ts +19 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +113 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/upgrade.d.ts +24 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +177 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/generators/deployment/docker-compose.d.ts +20 -0
- package/dist/generators/deployment/docker-compose.d.ts.map +1 -0
- package/dist/generators/deployment/docker-compose.js +95 -0
- package/dist/generators/deployment/docker-compose.js.map +1 -0
- package/dist/generators/deployment/dockerfile.d.ts +18 -0
- package/dist/generators/deployment/dockerfile.d.ts.map +1 -0
- package/dist/generators/deployment/dockerfile.js +99 -0
- package/dist/generators/deployment/dockerfile.js.map +1 -0
- package/dist/generators/deployment/pm2.d.ts +17 -0
- package/dist/generators/deployment/pm2.d.ts.map +1 -0
- package/dist/generators/deployment/pm2.js +59 -0
- package/dist/generators/deployment/pm2.js.map +1 -0
- package/dist/generators/deployment/secrets.d.ts +19 -0
- package/dist/generators/deployment/secrets.d.ts.map +1 -0
- package/dist/generators/deployment/secrets.js +41 -0
- package/dist/generators/deployment/secrets.js.map +1 -0
- package/dist/generators/deployment/shutdown.d.ts +17 -0
- package/dist/generators/deployment/shutdown.d.ts.map +1 -0
- package/dist/generators/deployment/shutdown.js +61 -0
- package/dist/generators/deployment/shutdown.js.map +1 -0
- package/dist/generators/deployment/wrangler.d.ts +25 -0
- package/dist/generators/deployment/wrangler.d.ts.map +1 -0
- package/dist/generators/deployment/wrangler.js +93 -0
- package/dist/generators/deployment/wrangler.js.map +1 -0
- package/dist/generators/file-generators.d.ts +38 -0
- package/dist/generators/file-generators.d.ts.map +1 -0
- package/dist/generators/file-generators.js +546 -0
- package/dist/generators/file-generators.js.map +1 -0
- package/dist/generators/module-generator.d.ts +33 -0
- package/dist/generators/module-generator.d.ts.map +1 -0
- package/dist/generators/module-generator.js +61 -0
- package/dist/generators/module-generator.js.map +1 -0
- package/dist/header-generator.d.ts +34 -0
- package/dist/header-generator.d.ts.map +1 -0
- package/dist/header-generator.js +77 -0
- package/dist/header-generator.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +177 -0
- package/dist/index.js.map +1 -0
- package/dist/linter/env-parity.d.ts +28 -0
- package/dist/linter/env-parity.d.ts.map +1 -0
- package/dist/linter/env-parity.js +59 -0
- package/dist/linter/env-parity.js.map +1 -0
- package/dist/linter.d.ts +23 -0
- package/dist/linter.d.ts.map +1 -0
- package/dist/linter.js +207 -0
- package/dist/linter.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
import { generateHeader } from '../header-generator.js';
|
|
11
|
+
// ─── Naming helpers ───────────────────────────────────────────────────────────
|
|
12
|
+
/** "user-profile" → "UserProfile" */
|
|
13
|
+
export function toPascalCase(name) {
|
|
14
|
+
return name
|
|
15
|
+
.split(/[-_\s]+/)
|
|
16
|
+
.map(w => w.charAt(0).toUpperCase() + w.slice(1))
|
|
17
|
+
.join('');
|
|
18
|
+
}
|
|
19
|
+
/** "user-profile" → "userProfile" */
|
|
20
|
+
export function toCamelCase(name) {
|
|
21
|
+
const pascal = toPascalCase(name);
|
|
22
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
23
|
+
}
|
|
24
|
+
/** "UserProfile" → "user_profiles" (simple pluralisation) */
|
|
25
|
+
export function toTableName(name) {
|
|
26
|
+
return name
|
|
27
|
+
.replace(/([A-Z])/g, '_$1')
|
|
28
|
+
.toLowerCase()
|
|
29
|
+
.replace(/^_/, '') + 's';
|
|
30
|
+
}
|
|
31
|
+
// ─── Individual file generators ───────────────────────────────────────────────
|
|
32
|
+
export function generateService(name) {
|
|
33
|
+
const pascal = toPascalCase(name);
|
|
34
|
+
const camel = toCamelCase(name);
|
|
35
|
+
const header = generateHeader(`src/modules/${name}/${name}.service.ts`);
|
|
36
|
+
return `${header}
|
|
37
|
+
|
|
38
|
+
import type { AppVariables } from 'vonosan/types'
|
|
39
|
+
import type { Context } from 'hono'
|
|
40
|
+
|
|
41
|
+
export class ${pascal}Service {
|
|
42
|
+
constructor(private readonly c: Context<{ Variables: AppVariables }>) {}
|
|
43
|
+
|
|
44
|
+
async findAll() {
|
|
45
|
+
// TODO: implement findAll
|
|
46
|
+
return []
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async findById(id: string) {
|
|
50
|
+
// TODO: implement findById
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async create(data: unknown) {
|
|
55
|
+
// TODO: implement create
|
|
56
|
+
return data
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async update(id: string, data: unknown) {
|
|
60
|
+
// TODO: implement update
|
|
61
|
+
return { id, ...data as object }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async delete(id: string) {
|
|
65
|
+
// TODO: implement delete
|
|
66
|
+
return { id }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const ${camel}Service = (c: Context<{ Variables: AppVariables }>) =>
|
|
71
|
+
new ${pascal}Service(c)
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
export function generateController(name) {
|
|
75
|
+
const pascal = toPascalCase(name);
|
|
76
|
+
const camel = toCamelCase(name);
|
|
77
|
+
const header = generateHeader(`src/modules/${name}/${name}.controller.ts`);
|
|
78
|
+
return `${header}
|
|
79
|
+
|
|
80
|
+
import type { Context } from 'hono'
|
|
81
|
+
import type { AppVariables } from 'vonosan/types'
|
|
82
|
+
import { success, error } from 'vonosan/server'
|
|
83
|
+
import { ${camel}Service } from './${name}.service.js'
|
|
84
|
+
|
|
85
|
+
export const ${pascal}Controller = {
|
|
86
|
+
async index(c: Context<{ Variables: AppVariables }>) {
|
|
87
|
+
const items = await ${camel}Service(c).findAll()
|
|
88
|
+
return c.json(success('${pascal} list', items))
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
async show(c: Context<{ Variables: AppVariables }>) {
|
|
92
|
+
const { id } = c.req.param()
|
|
93
|
+
const item = await ${camel}Service(c).findById(id)
|
|
94
|
+
if (!item) return c.json(error('${pascal} not found'), 404)
|
|
95
|
+
return c.json(success('${pascal} retrieved', item))
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
async store(c: Context<{ Variables: AppVariables }>) {
|
|
99
|
+
const body = await c.req.json()
|
|
100
|
+
const item = await ${camel}Service(c).create(body)
|
|
101
|
+
return c.json(success('${pascal} created', item), 201)
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
async update(c: Context<{ Variables: AppVariables }>) {
|
|
105
|
+
const { id } = c.req.param()
|
|
106
|
+
const body = await c.req.json()
|
|
107
|
+
const item = await ${camel}Service(c).update(id, body)
|
|
108
|
+
return c.json(success('${pascal} updated', item))
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
async destroy(c: Context<{ Variables: AppVariables }>) {
|
|
112
|
+
const { id } = c.req.param()
|
|
113
|
+
await ${camel}Service(c).delete(id)
|
|
114
|
+
return c.json(success('${pascal} deleted'))
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
export function generateDto(name) {
|
|
120
|
+
const pascal = toPascalCase(name);
|
|
121
|
+
const header = generateHeader(`src/modules/${name}/${name}.dto.ts`);
|
|
122
|
+
return `${header}
|
|
123
|
+
|
|
124
|
+
import { z } from 'zod'
|
|
125
|
+
|
|
126
|
+
export const Create${pascal}Schema = z.object({
|
|
127
|
+
// TODO: define create fields
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
export const Update${pascal}Schema = Create${pascal}Schema.partial()
|
|
131
|
+
|
|
132
|
+
export type Create${pascal}Dto = z.infer<typeof Create${pascal}Schema>
|
|
133
|
+
export type Update${pascal}Dto = z.infer<typeof Update${pascal}Schema>
|
|
134
|
+
`;
|
|
135
|
+
}
|
|
136
|
+
export function generateRoutes(name) {
|
|
137
|
+
const pascal = toPascalCase(name);
|
|
138
|
+
const header = generateHeader(`src/modules/${name}/${name}.routes.ts`);
|
|
139
|
+
return `${header}
|
|
140
|
+
|
|
141
|
+
import { Hono } from 'hono'
|
|
142
|
+
import type { AppVariables } from 'vonosan/types'
|
|
143
|
+
import { ${pascal}Controller } from './${name}.controller.js'
|
|
144
|
+
|
|
145
|
+
const router = new Hono<{ Variables: AppVariables }>()
|
|
146
|
+
|
|
147
|
+
router.get('/api/v1/${name}', ${pascal}Controller.index)
|
|
148
|
+
router.get('/api/v1/${name}/:id', ${pascal}Controller.show)
|
|
149
|
+
router.post('/api/v1/${name}', ${pascal}Controller.store)
|
|
150
|
+
router.put('/api/v1/${name}/:id', ${pascal}Controller.update)
|
|
151
|
+
router.delete('/api/v1/${name}/:id', ${pascal}Controller.destroy)
|
|
152
|
+
|
|
153
|
+
export default router
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
export function generateSchema(name, saas = false) {
|
|
157
|
+
const tableName = toTableName(toPascalCase(name));
|
|
158
|
+
const header = generateHeader(`src/modules/${name}/${name}.schema.ts`);
|
|
159
|
+
const softDeleteCol = saas ? `\n deleted_at: timestamp('deleted_at'),` : '';
|
|
160
|
+
return `${header}
|
|
161
|
+
|
|
162
|
+
import { pgTable, uuid, varchar, timestamp } from 'drizzle-orm/pg-core'
|
|
163
|
+
|
|
164
|
+
export const ${tableName} = pgTable('${tableName}', {
|
|
165
|
+
id: uuid('id').primaryKey().defaultRandom(),
|
|
166
|
+
// TODO: add columns
|
|
167
|
+
created_at: timestamp('created_at').defaultNow().notNull(),
|
|
168
|
+
updated_at: timestamp('updated_at').defaultNow().notNull(),${softDeleteCol}
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
export type ${toPascalCase(name)} = typeof ${tableName}.$inferSelect
|
|
172
|
+
export type New${toPascalCase(name)} = typeof ${tableName}.$inferInsert
|
|
173
|
+
`;
|
|
174
|
+
}
|
|
175
|
+
export function generateResource(name) {
|
|
176
|
+
const pascal = toPascalCase(name);
|
|
177
|
+
const header = generateHeader(`src/modules/${name}/${name}.resource.ts`);
|
|
178
|
+
return `${header}
|
|
179
|
+
|
|
180
|
+
import { buildPaginationMeta } from 'vonosan/server'
|
|
181
|
+
|
|
182
|
+
export class ${pascal}Resource {
|
|
183
|
+
static toResource(item: Record<string, unknown>, fields?: string[]) {
|
|
184
|
+
if (fields && fields.length > 0) {
|
|
185
|
+
return Object.fromEntries(
|
|
186
|
+
Object.entries(item).filter(([k]) => fields.includes(k)),
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
return item
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static toCollection(
|
|
193
|
+
items: Record<string, unknown>[],
|
|
194
|
+
total: number,
|
|
195
|
+
page: number,
|
|
196
|
+
limit: number,
|
|
197
|
+
) {
|
|
198
|
+
return {
|
|
199
|
+
${name}s: items.map(i => ${pascal}Resource.toResource(i)),
|
|
200
|
+
meta: buildPaginationMeta(page, limit, total),
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
`;
|
|
205
|
+
}
|
|
206
|
+
export function generatePolicy(name) {
|
|
207
|
+
const pascal = toPascalCase(name);
|
|
208
|
+
const header = generateHeader(`src/modules/${name}/${name}.policy.ts`);
|
|
209
|
+
return `${header}
|
|
210
|
+
|
|
211
|
+
import type { AuthAccount } from 'vonosan/types'
|
|
212
|
+
|
|
213
|
+
export class ${pascal}Policy {
|
|
214
|
+
static view(_user: AuthAccount, _resource?: unknown): boolean {
|
|
215
|
+
return true
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
static create(_user: AuthAccount): boolean {
|
|
219
|
+
return true
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
static update(user: AuthAccount, resource?: Record<string, unknown>): boolean {
|
|
223
|
+
// Example: only the owner or admin can update
|
|
224
|
+
if (user.currentRole === 'admin' || user.currentRole === 'superadmin') return true
|
|
225
|
+
return resource?.ownerId === user.id
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
static delete(user: AuthAccount, resource?: Record<string, unknown>): boolean {
|
|
229
|
+
if (user.currentRole === 'admin' || user.currentRole === 'superadmin') return true
|
|
230
|
+
return resource?.ownerId === user.id
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
`;
|
|
234
|
+
}
|
|
235
|
+
export function generateScopes(name) {
|
|
236
|
+
const pascal = toPascalCase(name);
|
|
237
|
+
const header = generateHeader(`src/modules/${name}/${name}.scopes.ts`);
|
|
238
|
+
return `${header}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* ${pascal} permission scopes.
|
|
242
|
+
* Register these in your auth module's scope registry.
|
|
243
|
+
*/
|
|
244
|
+
export const ${name.toUpperCase().replace(/-/g, '_')}_SCOPES = [
|
|
245
|
+
'${name}:read',
|
|
246
|
+
'${name}:write',
|
|
247
|
+
'${name}:delete',
|
|
248
|
+
'${name}:admin',
|
|
249
|
+
] as const
|
|
250
|
+
|
|
251
|
+
export type ${pascal}Scope = (typeof ${name.toUpperCase().replace(/-/g, '_')}_SCOPES)[number]
|
|
252
|
+
`;
|
|
253
|
+
}
|
|
254
|
+
export function generateMiddleware(name) {
|
|
255
|
+
const pascal = toPascalCase(name);
|
|
256
|
+
const header = generateHeader(`src/modules/${name}/${name}.middleware.ts`);
|
|
257
|
+
return `${header}
|
|
258
|
+
|
|
259
|
+
import type { Context, Next } from 'hono'
|
|
260
|
+
import type { AppVariables } from 'vonosan/types'
|
|
261
|
+
import { Logger } from 'vonosan/server'
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* ${pascal} middleware — add your logic here.
|
|
265
|
+
*/
|
|
266
|
+
export async function ${toCamelCase(name)}Middleware(
|
|
267
|
+
c: Context<{ Variables: AppVariables }>,
|
|
268
|
+
next: Next,
|
|
269
|
+
): Promise<void> {
|
|
270
|
+
Logger.debug('${pascal} middleware', { path: c.req.path })
|
|
271
|
+
await next()
|
|
272
|
+
}
|
|
273
|
+
`;
|
|
274
|
+
}
|
|
275
|
+
export function generatePage(name) {
|
|
276
|
+
const pascal = toPascalCase(name);
|
|
277
|
+
const header = generateHeader(`src/modules/${name}/index.page.vue`);
|
|
278
|
+
return `<!--
|
|
279
|
+
${header.replace(/^\/\*\*/, '').replace(/\s*\*\/$/, '').replace(/^\s*\* ?/gm, '').trim()}
|
|
280
|
+
-->
|
|
281
|
+
<script setup lang="ts">
|
|
282
|
+
import { use${pascal} } from './composables/use${pascal}.js'
|
|
283
|
+
|
|
284
|
+
const { items, loading, fetchAll } = use${pascal}()
|
|
285
|
+
|
|
286
|
+
onMounted(() => fetchAll())
|
|
287
|
+
</script>
|
|
288
|
+
|
|
289
|
+
<template>
|
|
290
|
+
<div>
|
|
291
|
+
<h1>${pascal}</h1>
|
|
292
|
+
<div v-if="loading">Loading…</div>
|
|
293
|
+
<ul v-else>
|
|
294
|
+
<li v-for="item in items" :key="(item as any).id">{{ item }}</li>
|
|
295
|
+
</ul>
|
|
296
|
+
</div>
|
|
297
|
+
</template>
|
|
298
|
+
`;
|
|
299
|
+
}
|
|
300
|
+
export function generateComposable(name) {
|
|
301
|
+
const pascal = toPascalCase(name);
|
|
302
|
+
const camel = toCamelCase(name);
|
|
303
|
+
const header = generateHeader(`src/modules/${name}/composables/use${pascal}.ts`);
|
|
304
|
+
return `${header}
|
|
305
|
+
|
|
306
|
+
import { ref } from 'vue'
|
|
307
|
+
import { useVonosanFetch } from 'vonosan/client'
|
|
308
|
+
|
|
309
|
+
export function use${pascal}() {
|
|
310
|
+
const items = ref<unknown[]>([])
|
|
311
|
+
const loading = ref(false)
|
|
312
|
+
const error = ref<string | null>(null)
|
|
313
|
+
|
|
314
|
+
async function fetchAll() {
|
|
315
|
+
loading.value = true
|
|
316
|
+
error.value = null
|
|
317
|
+
try {
|
|
318
|
+
const { data } = await useVonosanFetch('/api/v1/${name}')
|
|
319
|
+
items.value = (data as any)?.data ?? []
|
|
320
|
+
} catch (e) {
|
|
321
|
+
error.value = String(e)
|
|
322
|
+
} finally {
|
|
323
|
+
loading.value = false
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async function create(payload: unknown) {
|
|
328
|
+
const { data } = await useVonosanFetch('/api/v1/${name}', {
|
|
329
|
+
method: 'POST',
|
|
330
|
+
body: JSON.stringify(payload),
|
|
331
|
+
})
|
|
332
|
+
return (data as any)?.data
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return { items, loading, error, fetchAll, create }
|
|
336
|
+
}
|
|
337
|
+
`;
|
|
338
|
+
}
|
|
339
|
+
export function generateStore(name) {
|
|
340
|
+
const pascal = toPascalCase(name);
|
|
341
|
+
const header = generateHeader(`src/modules/${name}/stores/${name}.store.ts`);
|
|
342
|
+
return `${header}
|
|
343
|
+
|
|
344
|
+
import { defineStore } from 'pinia'
|
|
345
|
+
import { ref } from 'vue'
|
|
346
|
+
|
|
347
|
+
export const use${pascal}Store = defineStore('${name}', () => {
|
|
348
|
+
const items = ref<unknown[]>([])
|
|
349
|
+
const current = ref<unknown | null>(null)
|
|
350
|
+
|
|
351
|
+
function setItems(data: unknown[]) {
|
|
352
|
+
items.value = data
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function setCurrent(data: unknown | null) {
|
|
356
|
+
current.value = data
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return { items, current, setItems, setCurrent }
|
|
360
|
+
})
|
|
361
|
+
`;
|
|
362
|
+
}
|
|
363
|
+
export function generateMigration(name) {
|
|
364
|
+
const header = generateHeader(`src/db/migrations/${name}.sql`);
|
|
365
|
+
return `-- ${header.replace(/\/\*\*|\*\/|\* ?/g, '').trim()}
|
|
366
|
+
|
|
367
|
+
-- Migration: ${name}
|
|
368
|
+
-- Created: ${new Date().toISOString()}
|
|
369
|
+
|
|
370
|
+
-- TODO: write your migration SQL here
|
|
371
|
+
-- Example:
|
|
372
|
+
-- CREATE TABLE IF NOT EXISTS example (
|
|
373
|
+
-- id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
374
|
+
-- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
375
|
+
-- updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
376
|
+
-- );
|
|
377
|
+
`;
|
|
378
|
+
}
|
|
379
|
+
export function generateSeed(name) {
|
|
380
|
+
const header = generateHeader(`src/db/seeds/${name}.ts`);
|
|
381
|
+
return `${header}
|
|
382
|
+
|
|
383
|
+
import { Logger } from 'vonosan/server'
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Seed: ${name}
|
|
387
|
+
* Run with: vonosan db:seed ${name}
|
|
388
|
+
*/
|
|
389
|
+
export async function seed() {
|
|
390
|
+
Logger.info('Running seed: ${name}')
|
|
391
|
+
// TODO: insert seed data
|
|
392
|
+
Logger.info('Seed complete: ${name}')
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Allow direct execution: bun run src/db/seeds/${name}.ts
|
|
396
|
+
seed().catch((err) => {
|
|
397
|
+
Logger.error('Seed failed', { error: String(err) })
|
|
398
|
+
process.exit(1)
|
|
399
|
+
})
|
|
400
|
+
`;
|
|
401
|
+
}
|
|
402
|
+
export function generateTest(name) {
|
|
403
|
+
const pascal = toPascalCase(name);
|
|
404
|
+
const header = generateHeader(`src/modules/${name}/tests/${name}.unit.test.ts`);
|
|
405
|
+
return `${header}
|
|
406
|
+
|
|
407
|
+
import { describe, it, expect } from 'bun:test'
|
|
408
|
+
|
|
409
|
+
describe('${pascal} unit tests', () => {
|
|
410
|
+
it('should be defined', () => {
|
|
411
|
+
expect(true).toBe(true)
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
// TODO: add unit tests for ${pascal}Service, ${pascal}Controller, etc.
|
|
415
|
+
})
|
|
416
|
+
`;
|
|
417
|
+
}
|
|
418
|
+
export function generateIntegrationTest(name) {
|
|
419
|
+
const pascal = toPascalCase(name);
|
|
420
|
+
const header = generateHeader(`src/modules/${name}/tests/${name}.integration.test.ts`);
|
|
421
|
+
return `${header}
|
|
422
|
+
|
|
423
|
+
import { describe, it, expect } from 'bun:test'
|
|
424
|
+
|
|
425
|
+
describe('${pascal} integration tests', () => {
|
|
426
|
+
it('GET /api/v1/${name} returns 200', async () => {
|
|
427
|
+
// TODO: set up test app and make real HTTP requests
|
|
428
|
+
expect(true).toBe(true)
|
|
429
|
+
})
|
|
430
|
+
})
|
|
431
|
+
`;
|
|
432
|
+
}
|
|
433
|
+
export function generateE2ETest(name) {
|
|
434
|
+
const pascal = toPascalCase(name);
|
|
435
|
+
const header = generateHeader(`src/modules/${name}/tests/${name}.e2e.test.ts`);
|
|
436
|
+
return `${header}
|
|
437
|
+
|
|
438
|
+
import { describe, it, expect } from 'bun:test'
|
|
439
|
+
|
|
440
|
+
describe('${pascal} e2e tests', () => {
|
|
441
|
+
it('full CRUD flow', async () => {
|
|
442
|
+
// TODO: implement end-to-end test
|
|
443
|
+
expect(true).toBe(true)
|
|
444
|
+
})
|
|
445
|
+
})
|
|
446
|
+
`;
|
|
447
|
+
}
|
|
448
|
+
export function generateNotification(name) {
|
|
449
|
+
const pascal = toPascalCase(name);
|
|
450
|
+
const header = generateHeader(`src/modules/${name}/notifications/${name}.notification.ts`);
|
|
451
|
+
return `${header}
|
|
452
|
+
|
|
453
|
+
import { defineEmail } from 'vonosan/server'
|
|
454
|
+
|
|
455
|
+
export const ${toCamelCase(name)}Notification = defineEmail({
|
|
456
|
+
subject: '${pascal} Notification',
|
|
457
|
+
html: (data: Record<string, unknown>) => \`
|
|
458
|
+
<h1>${pascal}</h1>
|
|
459
|
+
<p>\${JSON.stringify(data)}</p>
|
|
460
|
+
\`,
|
|
461
|
+
text: (data: Record<string, unknown>) => \`${pascal}: \${JSON.stringify(data)}\`,
|
|
462
|
+
})
|
|
463
|
+
`;
|
|
464
|
+
}
|
|
465
|
+
export function generateJob(name) {
|
|
466
|
+
const pascal = toPascalCase(name);
|
|
467
|
+
const header = generateHeader(`src/jobs/${name}.job.ts`);
|
|
468
|
+
return `${header}
|
|
469
|
+
|
|
470
|
+
import { defineJob } from 'vonosan/server'
|
|
471
|
+
import { Logger } from 'vonosan/server'
|
|
472
|
+
|
|
473
|
+
export const ${toCamelCase(name)}Job = defineJob({
|
|
474
|
+
name: '${name}',
|
|
475
|
+
schedule: '0 * * * *', // every hour — adjust as needed
|
|
476
|
+
description: '${pascal} scheduled job',
|
|
477
|
+
async handler() {
|
|
478
|
+
Logger.info('Running job: ${name}')
|
|
479
|
+
// TODO: implement job logic
|
|
480
|
+
Logger.info('Job complete: ${name}')
|
|
481
|
+
},
|
|
482
|
+
})
|
|
483
|
+
`;
|
|
484
|
+
}
|
|
485
|
+
export function generateEmail(name) {
|
|
486
|
+
const pascal = toPascalCase(name);
|
|
487
|
+
const header = generateHeader(`src/emails/${name}.email.ts`);
|
|
488
|
+
return `${header}
|
|
489
|
+
|
|
490
|
+
import { defineEmail } from 'vonosan/server'
|
|
491
|
+
|
|
492
|
+
export const ${toCamelCase(name)}Email = defineEmail({
|
|
493
|
+
subject: '${pascal}',
|
|
494
|
+
html: (data: Record<string, unknown>) => \`
|
|
495
|
+
<!DOCTYPE html>
|
|
496
|
+
<html>
|
|
497
|
+
<body>
|
|
498
|
+
<h1>${pascal}</h1>
|
|
499
|
+
<p>Hello, \${data.name ?? 'there'}!</p>
|
|
500
|
+
<!-- TODO: add email content -->
|
|
501
|
+
</body>
|
|
502
|
+
</html>
|
|
503
|
+
\`,
|
|
504
|
+
text: (data: Record<string, unknown>) => \`Hello, \${data.name ?? 'there'}!\`,
|
|
505
|
+
})
|
|
506
|
+
`;
|
|
507
|
+
}
|
|
508
|
+
export function generateHelper(name) {
|
|
509
|
+
const pascal = toPascalCase(name);
|
|
510
|
+
const header = generateHeader(`src/shared/utils/${name}.ts`);
|
|
511
|
+
return `${header}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* ${pascal} helper utilities.
|
|
515
|
+
* Extracted shared logic — used in 2+ places.
|
|
516
|
+
*/
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* TODO: implement ${name} helper
|
|
520
|
+
*/
|
|
521
|
+
export function ${toCamelCase(name)}(input: unknown): unknown {
|
|
522
|
+
return input
|
|
523
|
+
}
|
|
524
|
+
`;
|
|
525
|
+
}
|
|
526
|
+
export function generateComponent(name) {
|
|
527
|
+
const pascal = toPascalCase(name);
|
|
528
|
+
const header = generateHeader(`src/modules/${name}/components/${pascal}.vue`);
|
|
529
|
+
return `<!--
|
|
530
|
+
${header.replace(/^\/\*\*/, '').replace(/\s*\*\/$/, '').replace(/^\s*\* ?/gm, '').trim()}
|
|
531
|
+
-->
|
|
532
|
+
<script setup lang="ts">
|
|
533
|
+
defineProps<{
|
|
534
|
+
// TODO: define props
|
|
535
|
+
}>()
|
|
536
|
+
</script>
|
|
537
|
+
|
|
538
|
+
<template>
|
|
539
|
+
<div class="${name}">
|
|
540
|
+
<!-- TODO: implement ${pascal} component -->
|
|
541
|
+
<slot />
|
|
542
|
+
</div>
|
|
543
|
+
</template>
|
|
544
|
+
`;
|
|
545
|
+
}
|
|
546
|
+
//# sourceMappingURL=file-generators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-generators.js","sourceRoot":"","sources":["../../src/generators/file-generators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
export interface ModuleGeneratorOptions {
|
|
11
|
+
/** Generate API files (routes, controller, service, dto, schema) */
|
|
12
|
+
api: boolean;
|
|
13
|
+
/** Generate frontend files (page, composable) */
|
|
14
|
+
frontend: boolean;
|
|
15
|
+
/** SaaS mode — adds deleted_at to schema */
|
|
16
|
+
saas: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface GeneratedFile {
|
|
19
|
+
path: string;
|
|
20
|
+
content: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generates all module files for `name` according to `options`.
|
|
24
|
+
* Returns the list of files that would be written (does NOT write to disk).
|
|
25
|
+
* Use `writeModule()` to persist them.
|
|
26
|
+
*/
|
|
27
|
+
export declare function generateModule(name: string, options: ModuleGeneratorOptions): GeneratedFile[];
|
|
28
|
+
/**
|
|
29
|
+
* Writes all generated files to disk.
|
|
30
|
+
* Throws if the module directory already exists (prevents overwriting).
|
|
31
|
+
*/
|
|
32
|
+
export declare function writeModule(name: string, files: GeneratedFile[], projectRoot?: string): void;
|
|
33
|
+
//# sourceMappingURL=module-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-generator.d.ts","sourceRoot":"","sources":["../../src/generators/module-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuBH,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,GAAG,EAAE,OAAO,CAAA;IACZ,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAA;IACjB,4CAA4C;IAC5C,IAAI,EAAE,OAAO,CAAA;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAID;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,sBAAsB,GAC9B,aAAa,EAAE,CA6BjB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,aAAa,EAAE,EACtB,WAAW,SAAgB,GAC1B,IAAI,CAeN"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { generateService, generateController, generateDto, generateRoutes, generateSchema, generateResource, generatePolicy, generateScopes, generatePage, generateComposable, generateTest, generateIntegrationTest, generateE2ETest, toPascalCase, } from './file-generators.js';
|
|
13
|
+
// ─── Module generator ─────────────────────────────────────────────────────────
|
|
14
|
+
/**
|
|
15
|
+
* Generates all module files for `name` according to `options`.
|
|
16
|
+
* Returns the list of files that would be written (does NOT write to disk).
|
|
17
|
+
* Use `writeModule()` to persist them.
|
|
18
|
+
*/
|
|
19
|
+
export function generateModule(name, options) {
|
|
20
|
+
const files = [];
|
|
21
|
+
const moduleDir = `src/modules/${name}`;
|
|
22
|
+
if (options.api) {
|
|
23
|
+
files.push({ path: `${moduleDir}/${name}.routes.ts`, content: generateRoutes(name) });
|
|
24
|
+
files.push({ path: `${moduleDir}/${name}.controller.ts`, content: generateController(name) });
|
|
25
|
+
files.push({ path: `${moduleDir}/${name}.service.ts`, content: generateService(name) });
|
|
26
|
+
files.push({ path: `${moduleDir}/${name}.dto.ts`, content: generateDto(name) });
|
|
27
|
+
files.push({ path: `${moduleDir}/${name}.schema.ts`, content: generateSchema(name, options.saas) });
|
|
28
|
+
files.push({ path: `${moduleDir}/${name}.resource.ts`, content: generateResource(name) });
|
|
29
|
+
files.push({ path: `${moduleDir}/${name}.policy.ts`, content: generatePolicy(name) });
|
|
30
|
+
files.push({ path: `${moduleDir}/${name}.scopes.ts`, content: generateScopes(name) });
|
|
31
|
+
// Tests
|
|
32
|
+
files.push({ path: `${moduleDir}/tests/${name}.unit.test.ts`, content: generateTest(name) });
|
|
33
|
+
files.push({ path: `${moduleDir}/tests/${name}.integration.test.ts`, content: generateIntegrationTest(name) });
|
|
34
|
+
files.push({ path: `${moduleDir}/tests/${name}.e2e.test.ts`, content: generateE2ETest(name) });
|
|
35
|
+
}
|
|
36
|
+
if (options.frontend) {
|
|
37
|
+
files.push({ path: `${moduleDir}/index.page.vue`, content: generatePage(name) });
|
|
38
|
+
files.push({
|
|
39
|
+
path: `${moduleDir}/composables/use${toPascalCase(name)}.ts`,
|
|
40
|
+
content: generateComposable(name),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return files;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Writes all generated files to disk.
|
|
47
|
+
* Throws if the module directory already exists (prevents overwriting).
|
|
48
|
+
*/
|
|
49
|
+
export function writeModule(name, files, projectRoot = process.cwd()) {
|
|
50
|
+
const moduleDir = join(projectRoot, 'src', 'modules', name);
|
|
51
|
+
if (existsSync(moduleDir)) {
|
|
52
|
+
throw new Error(`Module "${name}" already exists at ${moduleDir}. Remove it first or choose a different name.`);
|
|
53
|
+
}
|
|
54
|
+
for (const { path: filePath, content } of files) {
|
|
55
|
+
const absPath = join(projectRoot, filePath);
|
|
56
|
+
const dir = absPath.substring(0, absPath.lastIndexOf('/'));
|
|
57
|
+
mkdirSync(dir, { recursive: true });
|
|
58
|
+
writeFileSync(absPath, content, 'utf8');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=module-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-generator.js","sourceRoot":"","sources":["../../src/generators/module-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,uBAAuB,EACvB,eAAe,EACf,YAAY,GACb,MAAM,sBAAsB,CAAA;AAkB7B,iFAAiF;AAEjF;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,OAA+B;IAE/B,MAAM,KAAK,GAAoB,EAAE,CAAA;IACjC,MAAM,SAAS,GAAG,eAAe,IAAI,EAAE,CAAA;IAEvC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,IAAI,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACrF,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,IAAI,gBAAgB,EAAE,OAAO,EAAE,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC7F,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,IAAI,aAAa,EAAE,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACvF,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,IAAI,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC/E,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,IAAI,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACnG,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,IAAI,cAAc,EAAE,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACzF,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,IAAI,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACrF,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,IAAI,IAAI,YAAY,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAErF,QAAQ;QACR,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,UAAU,IAAI,eAAe,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC5F,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,UAAU,IAAI,sBAAsB,EAAE,OAAO,EAAE,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC9G,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,UAAU,IAAI,cAAc,EAAE,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChG,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,iBAAiB,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChF,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,GAAG,SAAS,mBAAmB,YAAY,CAAC,IAAI,CAAC,KAAK;YAC5D,OAAO,EAAE,kBAAkB,CAAC,IAAI,CAAC;SAClC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,KAAsB,EACtB,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;IAE3B,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;IAE3D,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,WAAW,IAAI,uBAAuB,SAAS,+CAA+C,CAC/F,CAAA;IACH,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,KAAK,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;QAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAA;QAC1D,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACnC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IACzC,CAAC;AACH,CAAC"}
|