@geekmidas/cli 0.25.0 → 0.27.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/{config-CTftATBX.cjs → config-BhryDQEq.cjs} +2 -2
- package/dist/{config-CTftATBX.cjs.map → config-BhryDQEq.cjs.map} +1 -1
- package/dist/{config-BogU0_oQ.mjs → config-C9bdq0l-.mjs} +2 -2
- package/dist/{config-BogU0_oQ.mjs.map → config-C9bdq0l-.mjs.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.mjs +2 -2
- package/dist/index-CWN-bgrO.d.mts.map +1 -1
- package/dist/index-DEWYvYvg.d.cts.map +1 -1
- package/dist/index.cjs +128 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +128 -27
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-DNbXfhXE.mjs → openapi-BCEFhkLh.mjs} +2 -2
- package/dist/{openapi-DNbXfhXE.mjs.map → openapi-BCEFhkLh.mjs.map} +1 -1
- package/dist/{openapi-BrhkPKM7.cjs → openapi-D82bBqG7.cjs} +2 -2
- package/dist/{openapi-BrhkPKM7.cjs.map → openapi-D82bBqG7.cjs.map} +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.mjs +3 -3
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-iWgBlX6h.cjs → workspace-CiZBOjf9.cjs} +1 -7
- package/dist/{workspace-iWgBlX6h.cjs.map → workspace-CiZBOjf9.cjs.map} +1 -1
- package/dist/{workspace-CPLEZDZf.mjs → workspace-DQjmv9lk.mjs} +1 -7
- package/dist/{workspace-CPLEZDZf.mjs.map → workspace-DQjmv9lk.mjs.map} +1 -1
- package/package.json +4 -4
- package/src/init/__tests__/generators.spec.ts +12 -6
- package/src/init/__tests__/init.spec.ts +18 -6
- package/src/init/generators/models.ts +49 -19
- package/src/init/templates/api.ts +57 -3
- package/src/init/templates/minimal.ts +8 -0
- package/src/init/templates/serverless.ts +9 -0
- package/src/init/templates/worker.ts +9 -1
- package/src/init/versions.ts +1 -1
- package/src/workspace/__tests__/index.spec.ts +5 -6
- package/src/workspace/__tests__/schema.spec.ts +5 -5
- package/src/workspace/schema.ts +1 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekmidas/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"openapi-typescript": "^7.4.2",
|
|
50
50
|
"prompts": "~2.4.2",
|
|
51
51
|
"@geekmidas/constructs": "~0.6.0",
|
|
52
|
-
"@geekmidas/envkit": "~0.4.0",
|
|
53
|
-
"@geekmidas/logger": "~0.4.0",
|
|
54
52
|
"@geekmidas/schema": "~0.1.0",
|
|
55
|
-
"@geekmidas/errors": "~0.1.0"
|
|
53
|
+
"@geekmidas/errors": "~0.1.0",
|
|
54
|
+
"@geekmidas/envkit": "~0.4.0",
|
|
55
|
+
"@geekmidas/logger": "~0.4.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/lodash.kebabcase": "^4.1.9",
|
|
@@ -297,7 +297,8 @@ describe('generateModelsPackage', () => {
|
|
|
297
297
|
const paths = files.map((f) => f.path);
|
|
298
298
|
expect(paths).toContain('packages/models/package.json');
|
|
299
299
|
expect(paths).toContain('packages/models/tsconfig.json');
|
|
300
|
-
expect(paths).toContain('packages/models/src/
|
|
300
|
+
expect(paths).toContain('packages/models/src/common.ts');
|
|
301
|
+
expect(paths).toContain('packages/models/src/user.ts');
|
|
301
302
|
});
|
|
302
303
|
|
|
303
304
|
it('should use correct package name', () => {
|
|
@@ -335,12 +336,17 @@ describe('generateModelsPackage', () => {
|
|
|
335
336
|
apiPath: 'apps/api',
|
|
336
337
|
};
|
|
337
338
|
const files = generateModelsPackage(options);
|
|
338
|
-
const
|
|
339
|
-
(f) => f.path === 'packages/models/src/
|
|
339
|
+
const userTs = files.find(
|
|
340
|
+
(f) => f.path === 'packages/models/src/user.ts',
|
|
340
341
|
);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
342
|
+
const commonTs = files.find(
|
|
343
|
+
(f) => f.path === 'packages/models/src/common.ts',
|
|
344
|
+
);
|
|
345
|
+
expect(userTs?.content).toContain('UserSchema');
|
|
346
|
+
expect(userTs?.content).toContain('UserResponseSchema');
|
|
347
|
+
expect(userTs?.content).toContain("import { z } from 'zod'");
|
|
348
|
+
expect(commonTs?.content).toContain('PaginationSchema');
|
|
349
|
+
expect(commonTs?.content).toContain('IdSchema');
|
|
344
350
|
});
|
|
345
351
|
|
|
346
352
|
it('should extend root tsconfig', () => {
|
|
@@ -176,7 +176,10 @@ describe('initCommand', () => {
|
|
|
176
176
|
expect(
|
|
177
177
|
existsSync(join(projectDir, 'packages/models/tsconfig.json')),
|
|
178
178
|
).toBe(true);
|
|
179
|
-
expect(existsSync(join(projectDir, 'packages/models/src/
|
|
179
|
+
expect(existsSync(join(projectDir, 'packages/models/src/common.ts'))).toBe(
|
|
180
|
+
true,
|
|
181
|
+
);
|
|
182
|
+
expect(existsSync(join(projectDir, 'packages/models/src/user.ts'))).toBe(
|
|
180
183
|
true,
|
|
181
184
|
);
|
|
182
185
|
});
|
|
@@ -265,14 +268,23 @@ describe('initCommand', () => {
|
|
|
265
268
|
expect(pkg.name).toBe('@my-monorepo/models');
|
|
266
269
|
expect(pkg.dependencies.zod).toBeDefined();
|
|
267
270
|
|
|
268
|
-
const
|
|
271
|
+
const userPath = join(
|
|
272
|
+
tempDir,
|
|
273
|
+
'my-monorepo',
|
|
274
|
+
'packages/models/src/user.ts',
|
|
275
|
+
);
|
|
276
|
+
const userContent = await readFile(userPath, 'utf-8');
|
|
277
|
+
expect(userContent).toContain('UserSchema');
|
|
278
|
+
expect(userContent).toContain('UserResponseSchema');
|
|
279
|
+
|
|
280
|
+
const commonPath = join(
|
|
269
281
|
tempDir,
|
|
270
282
|
'my-monorepo',
|
|
271
|
-
'packages/models/src/
|
|
283
|
+
'packages/models/src/common.ts',
|
|
272
284
|
);
|
|
273
|
-
const
|
|
274
|
-
expect(
|
|
275
|
-
expect(
|
|
285
|
+
const commonContent = await readFile(commonPath, 'utf-8');
|
|
286
|
+
expect(commonContent).toContain('PaginationSchema');
|
|
287
|
+
expect(commonContent).toContain('IdSchema');
|
|
276
288
|
});
|
|
277
289
|
|
|
278
290
|
it('should support custom API path', async () => {
|
|
@@ -55,26 +55,26 @@ export function generateModelsPackage(
|
|
|
55
55
|
exclude: ['node_modules', 'dist'],
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
const
|
|
58
|
+
// common.ts - shared utility schemas
|
|
59
|
+
const commonTs = `import { z } from 'zod';
|
|
60
60
|
|
|
61
61
|
// ============================================
|
|
62
62
|
// Common Schemas
|
|
63
63
|
// ============================================
|
|
64
64
|
|
|
65
|
-
export const
|
|
65
|
+
export const IdSchema = z.string().uuid();
|
|
66
66
|
|
|
67
|
-
export const
|
|
67
|
+
export const TimestampsSchema = z.object({
|
|
68
68
|
createdAt: z.coerce.date(),
|
|
69
69
|
updatedAt: z.coerce.date(),
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
export const
|
|
72
|
+
export const PaginationSchema = z.object({
|
|
73
73
|
page: z.coerce.number().int().positive().default(1),
|
|
74
74
|
limit: z.coerce.number().int().positive().max(100).default(20),
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
export const
|
|
77
|
+
export const PaginatedResponseSchema = <T extends z.ZodTypeAny>(itemSchema: T) =>
|
|
78
78
|
z.object({
|
|
79
79
|
items: z.array(itemSchema),
|
|
80
80
|
total: z.number(),
|
|
@@ -83,35 +83,61 @@ export const paginatedResponseSchema = <T extends z.ZodTypeAny>(itemSchema: T) =
|
|
|
83
83
|
totalPages: z.number(),
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
+
// ============================================
|
|
87
|
+
// Type Exports
|
|
88
|
+
// ============================================
|
|
89
|
+
|
|
90
|
+
export type Id = z.infer<typeof IdSchema>;
|
|
91
|
+
export type Timestamps = z.infer<typeof TimestampsSchema>;
|
|
92
|
+
export type Pagination = z.infer<typeof PaginationSchema>;
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
// user.ts - user-related schemas
|
|
96
|
+
const userTs = `import { z } from 'zod';
|
|
97
|
+
import { IdSchema, TimestampsSchema } from './common.js';
|
|
98
|
+
|
|
86
99
|
// ============================================
|
|
87
100
|
// User Schemas
|
|
88
101
|
// ============================================
|
|
89
102
|
|
|
90
|
-
export const
|
|
91
|
-
id:
|
|
103
|
+
export const UserSchema = z.object({
|
|
104
|
+
id: IdSchema,
|
|
92
105
|
email: z.string().email(),
|
|
93
106
|
name: z.string().min(1).max(100),
|
|
94
|
-
...
|
|
107
|
+
...TimestampsSchema.shape,
|
|
95
108
|
});
|
|
96
109
|
|
|
97
|
-
export const
|
|
110
|
+
export const CreateUserSchema = UserSchema.omit({
|
|
98
111
|
id: true,
|
|
99
112
|
createdAt: true,
|
|
100
113
|
updatedAt: true,
|
|
101
114
|
});
|
|
102
115
|
|
|
103
|
-
export const
|
|
116
|
+
export const UpdateUserSchema = CreateUserSchema.partial();
|
|
117
|
+
|
|
118
|
+
// ============================================
|
|
119
|
+
// Response Schemas
|
|
120
|
+
// ============================================
|
|
121
|
+
|
|
122
|
+
export const UserResponseSchema = UserSchema.pick({
|
|
123
|
+
id: true,
|
|
124
|
+
name: true,
|
|
125
|
+
email: true,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
export const ListUsersResponseSchema = z.object({
|
|
129
|
+
users: z.array(UserSchema.pick({ id: true, name: true })),
|
|
130
|
+
});
|
|
104
131
|
|
|
105
132
|
// ============================================
|
|
106
133
|
// Type Exports
|
|
107
134
|
// ============================================
|
|
108
135
|
|
|
109
|
-
export type
|
|
110
|
-
export type
|
|
111
|
-
export type
|
|
112
|
-
export type
|
|
113
|
-
export type
|
|
114
|
-
export type UpdateUser = z.infer<typeof updateUserSchema>;
|
|
136
|
+
export type User = z.infer<typeof UserSchema>;
|
|
137
|
+
export type CreateUser = z.infer<typeof CreateUserSchema>;
|
|
138
|
+
export type UpdateUser = z.infer<typeof UpdateUserSchema>;
|
|
139
|
+
export type UserResponse = z.infer<typeof UserResponseSchema>;
|
|
140
|
+
export type ListUsersResponse = z.infer<typeof ListUsersResponseSchema>;
|
|
115
141
|
`;
|
|
116
142
|
|
|
117
143
|
return [
|
|
@@ -124,8 +150,12 @@ export type UpdateUser = z.infer<typeof updateUserSchema>;
|
|
|
124
150
|
content: `${JSON.stringify(tsConfig, null, 2)}\n`,
|
|
125
151
|
},
|
|
126
152
|
{
|
|
127
|
-
path: 'packages/models/src/
|
|
128
|
-
content:
|
|
153
|
+
path: 'packages/models/src/common.ts',
|
|
154
|
+
content: commonTs,
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
path: 'packages/models/src/user.ts',
|
|
158
|
+
content: userTs,
|
|
129
159
|
},
|
|
130
160
|
];
|
|
131
161
|
}
|
|
@@ -10,10 +10,13 @@ export const apiTemplate: TemplateConfig = {
|
|
|
10
10
|
description: 'Full API with auth, database, services',
|
|
11
11
|
|
|
12
12
|
dependencies: {
|
|
13
|
+
'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],
|
|
13
14
|
'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],
|
|
14
15
|
'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],
|
|
15
16
|
'@geekmidas/events': GEEKMIDAS_VERSIONS['@geekmidas/events'],
|
|
16
17
|
'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],
|
|
18
|
+
'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],
|
|
19
|
+
'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],
|
|
17
20
|
'@geekmidas/services': GEEKMIDAS_VERSIONS['@geekmidas/services'],
|
|
18
21
|
'@geekmidas/errors': GEEKMIDAS_VERSIONS['@geekmidas/errors'],
|
|
19
22
|
'@geekmidas/auth': GEEKMIDAS_VERSIONS['@geekmidas/auth'],
|
|
@@ -44,13 +47,16 @@ export const apiTemplate: TemplateConfig = {
|
|
|
44
47
|
},
|
|
45
48
|
|
|
46
49
|
files: (options: TemplateOptions): GeneratedFile[] => {
|
|
47
|
-
const { loggerType, routesStructure } = options;
|
|
50
|
+
const { loggerType, routesStructure, monorepo, name } = options;
|
|
48
51
|
|
|
49
52
|
const loggerContent = `import { createLogger } from '@geekmidas/logger/${loggerType}';
|
|
50
53
|
|
|
51
54
|
export const logger = createLogger();
|
|
52
55
|
`;
|
|
53
56
|
|
|
57
|
+
// Models package import path for monorepo
|
|
58
|
+
const modelsImport = monorepo ? `@${name}/models` : null;
|
|
59
|
+
|
|
54
60
|
// Get route path based on structure
|
|
55
61
|
const getRoutePath = (file: string) => {
|
|
56
62
|
switch (routesStructure) {
|
|
@@ -98,9 +104,14 @@ export const config = envParser
|
|
|
98
104
|
{
|
|
99
105
|
path: getRoutePath('health.ts'),
|
|
100
106
|
content: `import { e } from '@geekmidas/constructs/endpoints';
|
|
107
|
+
import { z } from 'zod';
|
|
101
108
|
|
|
102
109
|
export const healthEndpoint = e
|
|
103
110
|
.get('/health')
|
|
111
|
+
.output(z.object({
|
|
112
|
+
status: z.string(),
|
|
113
|
+
timestamp: z.string(),
|
|
114
|
+
}))
|
|
104
115
|
.handle(async () => ({
|
|
105
116
|
status: 'ok',
|
|
106
117
|
timestamp: new Date().toISOString(),
|
|
@@ -111,10 +122,33 @@ export const healthEndpoint = e
|
|
|
111
122
|
// users endpoints
|
|
112
123
|
{
|
|
113
124
|
path: getRoutePath('users/list.ts'),
|
|
114
|
-
content:
|
|
125
|
+
content: modelsImport
|
|
126
|
+
? `import { e } from '@geekmidas/constructs/endpoints';
|
|
127
|
+
import { ListUsersResponseSchema } from '${modelsImport}/user';
|
|
115
128
|
|
|
116
129
|
export const listUsersEndpoint = e
|
|
117
130
|
.get('/users')
|
|
131
|
+
.output(ListUsersResponseSchema)
|
|
132
|
+
.handle(async () => ({
|
|
133
|
+
users: [
|
|
134
|
+
{ id: '1', name: 'Alice' },
|
|
135
|
+
{ id: '2', name: 'Bob' },
|
|
136
|
+
],
|
|
137
|
+
}));
|
|
138
|
+
`
|
|
139
|
+
: `import { e } from '@geekmidas/constructs/endpoints';
|
|
140
|
+
import { z } from 'zod';
|
|
141
|
+
|
|
142
|
+
const UserSchema = z.object({
|
|
143
|
+
id: z.string(),
|
|
144
|
+
name: z.string(),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
export const listUsersEndpoint = e
|
|
148
|
+
.get('/users')
|
|
149
|
+
.output(z.object({
|
|
150
|
+
users: z.array(UserSchema),
|
|
151
|
+
}))
|
|
118
152
|
.handle(async () => ({
|
|
119
153
|
users: [
|
|
120
154
|
{ id: '1', name: 'Alice' },
|
|
@@ -125,12 +159,32 @@ export const listUsersEndpoint = e
|
|
|
125
159
|
},
|
|
126
160
|
{
|
|
127
161
|
path: getRoutePath('users/get.ts'),
|
|
128
|
-
content:
|
|
162
|
+
content: modelsImport
|
|
163
|
+
? `import { e } from '@geekmidas/constructs/endpoints';
|
|
164
|
+
import { z } from 'zod';
|
|
165
|
+
import { UserResponseSchema } from '${modelsImport}/user';
|
|
166
|
+
|
|
167
|
+
export const getUserEndpoint = e
|
|
168
|
+
.get('/users/:id')
|
|
169
|
+
.params(z.object({ id: z.string() }))
|
|
170
|
+
.output(UserResponseSchema)
|
|
171
|
+
.handle(async ({ params }) => ({
|
|
172
|
+
id: params.id,
|
|
173
|
+
name: 'Alice',
|
|
174
|
+
email: 'alice@example.com',
|
|
175
|
+
}));
|
|
176
|
+
`
|
|
177
|
+
: `import { e } from '@geekmidas/constructs/endpoints';
|
|
129
178
|
import { z } from 'zod';
|
|
130
179
|
|
|
131
180
|
export const getUserEndpoint = e
|
|
132
181
|
.get('/users/:id')
|
|
133
182
|
.params(z.object({ id: z.string() }))
|
|
183
|
+
.output(z.object({
|
|
184
|
+
id: z.string(),
|
|
185
|
+
name: z.string(),
|
|
186
|
+
email: z.string().email(),
|
|
187
|
+
}))
|
|
134
188
|
.handle(async ({ params }) => ({
|
|
135
189
|
id: params.id,
|
|
136
190
|
name: 'Alice',
|
|
@@ -10,9 +10,12 @@ export const minimalTemplate: TemplateConfig = {
|
|
|
10
10
|
description: 'Basic health endpoint',
|
|
11
11
|
|
|
12
12
|
dependencies: {
|
|
13
|
+
'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],
|
|
13
14
|
'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],
|
|
14
15
|
'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],
|
|
15
16
|
'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],
|
|
17
|
+
'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],
|
|
18
|
+
'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],
|
|
16
19
|
'@hono/node-server': '~1.14.1',
|
|
17
20
|
hono: '~4.8.2',
|
|
18
21
|
pino: '~9.6.0',
|
|
@@ -89,9 +92,14 @@ export const config = envParser
|
|
|
89
92
|
{
|
|
90
93
|
path: getRoutePath('health.ts'),
|
|
91
94
|
content: `import { e } from '@geekmidas/constructs/endpoints';
|
|
95
|
+
import { z } from 'zod';
|
|
92
96
|
|
|
93
97
|
export const healthEndpoint = e
|
|
94
98
|
.get('/health')
|
|
99
|
+
.output(z.object({
|
|
100
|
+
status: z.string(),
|
|
101
|
+
timestamp: z.string(),
|
|
102
|
+
}))
|
|
95
103
|
.handle(async () => ({
|
|
96
104
|
status: 'ok',
|
|
97
105
|
timestamp: new Date().toISOString(),
|
|
@@ -10,10 +10,13 @@ export const serverlessTemplate: TemplateConfig = {
|
|
|
10
10
|
description: 'AWS Lambda handlers',
|
|
11
11
|
|
|
12
12
|
dependencies: {
|
|
13
|
+
'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],
|
|
13
14
|
'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],
|
|
14
15
|
'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],
|
|
15
16
|
'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],
|
|
16
17
|
'@geekmidas/cloud': GEEKMIDAS_VERSIONS['@geekmidas/cloud'],
|
|
18
|
+
'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],
|
|
19
|
+
'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],
|
|
17
20
|
'@hono/node-server': '~1.14.1',
|
|
18
21
|
hono: '~4.8.2',
|
|
19
22
|
pino: '~9.6.0',
|
|
@@ -91,9 +94,15 @@ export const config = envParser
|
|
|
91
94
|
{
|
|
92
95
|
path: getRoutePath('health.ts'),
|
|
93
96
|
content: `import { e } from '@geekmidas/constructs/endpoints';
|
|
97
|
+
import { z } from 'zod';
|
|
94
98
|
|
|
95
99
|
export const healthEndpoint = e
|
|
96
100
|
.get('/health')
|
|
101
|
+
.output(z.object({
|
|
102
|
+
status: z.string(),
|
|
103
|
+
timestamp: z.string(),
|
|
104
|
+
region: z.string(),
|
|
105
|
+
}))
|
|
97
106
|
.handle(async () => ({
|
|
98
107
|
status: 'ok',
|
|
99
108
|
timestamp: new Date().toISOString(),
|
|
@@ -10,10 +10,13 @@ export const workerTemplate: TemplateConfig = {
|
|
|
10
10
|
description: 'Background job processing',
|
|
11
11
|
|
|
12
12
|
dependencies: {
|
|
13
|
+
'@geekmidas/audit': GEEKMIDAS_VERSIONS['@geekmidas/audit'],
|
|
13
14
|
'@geekmidas/constructs': GEEKMIDAS_VERSIONS['@geekmidas/constructs'],
|
|
14
15
|
'@geekmidas/envkit': GEEKMIDAS_VERSIONS['@geekmidas/envkit'],
|
|
15
|
-
'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],
|
|
16
16
|
'@geekmidas/events': GEEKMIDAS_VERSIONS['@geekmidas/events'],
|
|
17
|
+
'@geekmidas/logger': GEEKMIDAS_VERSIONS['@geekmidas/logger'],
|
|
18
|
+
'@geekmidas/rate-limit': GEEKMIDAS_VERSIONS['@geekmidas/rate-limit'],
|
|
19
|
+
'@geekmidas/schema': GEEKMIDAS_VERSIONS['@geekmidas/schema'],
|
|
17
20
|
'@hono/node-server': '~1.14.1',
|
|
18
21
|
hono: '~4.8.2',
|
|
19
22
|
pino: '~9.6.0',
|
|
@@ -90,9 +93,14 @@ export const config = envParser
|
|
|
90
93
|
{
|
|
91
94
|
path: getRoutePath('health.ts'),
|
|
92
95
|
content: `import { e } from '@geekmidas/constructs/endpoints';
|
|
96
|
+
import { z } from 'zod';
|
|
93
97
|
|
|
94
98
|
export const healthEndpoint = e
|
|
95
99
|
.get('/health')
|
|
100
|
+
.output(z.object({
|
|
101
|
+
status: z.string(),
|
|
102
|
+
timestamp: z.string(),
|
|
103
|
+
}))
|
|
96
104
|
.handle(async () => ({
|
|
97
105
|
status: 'ok',
|
|
98
106
|
timestamp: new Date().toISOString(),
|
package/src/init/versions.ts
CHANGED
|
@@ -41,20 +41,19 @@ describe('defineWorkspace', () => {
|
|
|
41
41
|
);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
it('should
|
|
44
|
+
it('should allow backend apps without routes (e.g., auth servers)', () => {
|
|
45
45
|
const config = {
|
|
46
46
|
apps: {
|
|
47
|
-
|
|
47
|
+
auth: {
|
|
48
48
|
type: 'backend',
|
|
49
|
-
path: 'apps/
|
|
49
|
+
path: 'apps/auth',
|
|
50
50
|
port: 3000,
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
53
|
} as WorkspaceConfig;
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
);
|
|
55
|
+
// Should not throw - routes are optional for backend apps
|
|
56
|
+
expect(() => defineWorkspace(config)).not.toThrow();
|
|
58
57
|
});
|
|
59
58
|
});
|
|
60
59
|
|
|
@@ -142,21 +142,21 @@ describe('WorkspaceConfigSchema', () => {
|
|
|
142
142
|
expect(result.error).toBeDefined();
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
-
it('should
|
|
145
|
+
it('should allow backend app without routes (e.g., auth servers)', () => {
|
|
146
146
|
const config = {
|
|
147
147
|
apps: {
|
|
148
|
-
|
|
148
|
+
auth: {
|
|
149
149
|
type: 'backend' as const,
|
|
150
|
-
path: 'apps/
|
|
150
|
+
path: 'apps/auth',
|
|
151
151
|
port: 3000,
|
|
152
|
-
//
|
|
152
|
+
// Routes are optional for backend apps
|
|
153
153
|
},
|
|
154
154
|
},
|
|
155
155
|
};
|
|
156
156
|
|
|
157
157
|
const result = safeValidateWorkspaceConfig(config);
|
|
158
158
|
|
|
159
|
-
expect(result.success).toBe(
|
|
159
|
+
expect(result.success).toBe(true);
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
it('should reject frontend app without framework', () => {
|
package/src/workspace/schema.ts
CHANGED
|
@@ -203,19 +203,7 @@ const AppConfigSchema = z
|
|
|
203
203
|
framework: z.enum(['nextjs']).optional(),
|
|
204
204
|
client: ClientConfigSchema.optional(),
|
|
205
205
|
})
|
|
206
|
-
|
|
207
|
-
(data) => {
|
|
208
|
-
// Backend apps must have routes
|
|
209
|
-
if (data.type === 'backend' && !data.routes) {
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
212
|
-
return true;
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
message: 'Backend apps must have routes defined',
|
|
216
|
-
path: ['routes'],
|
|
217
|
-
},
|
|
218
|
-
)
|
|
206
|
+
// Note: routes is optional for backend apps - some backends like auth servers don't use routes
|
|
219
207
|
.refine(
|
|
220
208
|
(data) => {
|
|
221
209
|
// Frontend apps must have framework
|