create-velox-app 0.6.96 → 0.6.98
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/CHANGELOG.md +12 -0
- package/dist/templates/auth.js +4 -0
- package/dist/templates/rsc-auth.js +4 -0
- package/package.json +1 -1
- package/src/templates/source/api/procedures/profiles.auth.ts +59 -0
- package/src/templates/source/api/router.auth.ts +3 -1
- package/src/templates/source/api/routes.auth.ts +4 -0
- package/src/templates/source/rsc-auth/src/api/handler.ts +8 -2
- package/src/templates/source/rsc-auth/src/api/procedures/profiles.ts +59 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# create-velox-app
|
|
2
2
|
|
|
3
|
+
## 0.6.98
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat(router): nested resource schema relations with .hasOne() / .hasMany()
|
|
8
|
+
|
|
9
|
+
## 0.6.97
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- sync zod dependency version
|
|
14
|
+
|
|
3
15
|
## 0.6.96
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/templates/auth.js
CHANGED
|
@@ -56,6 +56,9 @@ function generateRoutesTs() {
|
|
|
56
56
|
function generateConfigDatabase(config) {
|
|
57
57
|
return compileTemplate('api/config/database.ts', config);
|
|
58
58
|
}
|
|
59
|
+
function generateProfileProcedures() {
|
|
60
|
+
return compileTemplate('api/procedures/profiles.auth.ts', AUTH_CONFIG);
|
|
61
|
+
}
|
|
59
62
|
function generateHealthProcedures() {
|
|
60
63
|
return compileTemplate('api/procedures/health.ts', AUTH_CONFIG);
|
|
61
64
|
}
|
|
@@ -101,6 +104,7 @@ export function generateAuthTemplate(config) {
|
|
|
101
104
|
{ path: 'apps/api/src/procedures/health.ts', content: generateHealthProcedures() },
|
|
102
105
|
{ path: 'apps/api/src/procedures/auth.ts', content: generateAuthProcedures() },
|
|
103
106
|
{ path: 'apps/api/src/procedures/users.ts', content: generateUserProceduresWithAuth() },
|
|
107
|
+
{ path: 'apps/api/src/procedures/profiles.ts', content: generateProfileProcedures() },
|
|
104
108
|
{ path: 'apps/api/src/schemas/user.ts', content: generateUserSchema() },
|
|
105
109
|
{ path: 'apps/api/src/schemas/auth.ts', content: generateAuthSchema() },
|
|
106
110
|
{ path: 'apps/api/src/schemas/health.ts', content: generateHealthSchema() },
|
|
@@ -125,6 +125,9 @@ function generateUserProcedures() {
|
|
|
125
125
|
function generateAuthProcedures() {
|
|
126
126
|
return compileTemplate('rsc-auth/src/api/procedures/auth.ts', RSC_CONFIG);
|
|
127
127
|
}
|
|
128
|
+
function generateProfileProcedures() {
|
|
129
|
+
return compileTemplate('rsc-auth/src/api/procedures/profiles.ts', RSC_CONFIG);
|
|
130
|
+
}
|
|
128
131
|
// Schemas
|
|
129
132
|
function generateUserSchemas() {
|
|
130
133
|
return compileTemplate('rsc-auth/src/api/schemas/user.ts', RSC_CONFIG);
|
|
@@ -186,6 +189,7 @@ export function generateRscAuthTemplate(config) {
|
|
|
186
189
|
{ path: 'src/api/procedures/health.ts', content: generateHealthProcedures() },
|
|
187
190
|
{ path: 'src/api/procedures/users.ts', content: generateUserProcedures() },
|
|
188
191
|
{ path: 'src/api/procedures/auth.ts', content: generateAuthProcedures() },
|
|
192
|
+
{ path: 'src/api/procedures/profiles.ts', content: generateProfileProcedures() },
|
|
189
193
|
{ path: 'src/api/schemas/user.ts', content: generateUserSchemas() },
|
|
190
194
|
{ path: 'src/api/schemas/auth.ts', content: generateAuthSchemas() },
|
|
191
195
|
{ path: 'src/api/utils/auth.ts', content: generateAuthUtils() },
|
package/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile Procedures (Resource API Example)
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates field-level visibility using tagged resource schemas:
|
|
5
|
+
* - Public: GET /api/profiles/:id → { id, name }
|
|
6
|
+
* Uses handler-level projection: resource(data, Schema.public)
|
|
7
|
+
* - Authenticated: GET /api/profiles/:id/full → { id, name, email }
|
|
8
|
+
* Uses procedure-level auto-projection: .resource(Schema.authenticated)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
authenticatedNarrow,
|
|
13
|
+
NotFoundError,
|
|
14
|
+
procedure,
|
|
15
|
+
procedures,
|
|
16
|
+
resource,
|
|
17
|
+
resourceSchema,
|
|
18
|
+
z,
|
|
19
|
+
} from '@veloxts/velox';
|
|
20
|
+
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Resource Schema (field-level visibility)
|
|
23
|
+
// ============================================================================
|
|
24
|
+
|
|
25
|
+
const UserProfileSchema = resourceSchema()
|
|
26
|
+
.public('id', z.string().uuid())
|
|
27
|
+
.public('name', z.string())
|
|
28
|
+
.authenticated('email', z.string().email())
|
|
29
|
+
.build();
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Profile Procedures
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
export const profileProcedures = procedures('profiles', {
|
|
36
|
+
// Public: GET /api/profiles/:id → { id, name }
|
|
37
|
+
// Handler-level projection: resource(data, Schema.public) returns projected data directly
|
|
38
|
+
getProfile: procedure()
|
|
39
|
+
.input(z.object({ id: z.string().uuid() }))
|
|
40
|
+
.resource(UserProfileSchema.public)
|
|
41
|
+
.query(async ({ input, ctx }) => {
|
|
42
|
+
const user = await ctx.db.user.findUnique({ where: { id: input.id } });
|
|
43
|
+
if (!user) throw new NotFoundError(`User '${input.id}' not found`);
|
|
44
|
+
return resource(user, UserProfileSchema.public);
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
// Authenticated: GET /api/profiles/:id/full → { id, name, email }
|
|
48
|
+
// Procedure-level auto-projection: .resource(Schema.authenticated) auto-projects the return value
|
|
49
|
+
getFullProfile: procedure()
|
|
50
|
+
.rest({ method: 'GET', path: '/profiles/:id/full' })
|
|
51
|
+
.guardNarrow(authenticatedNarrow)
|
|
52
|
+
.input(z.object({ id: z.string().uuid() }))
|
|
53
|
+
.resource(UserProfileSchema.authenticated)
|
|
54
|
+
.query(async ({ input, ctx }) => {
|
|
55
|
+
const user = await ctx.db.user.findUnique({ where: { id: input.id } });
|
|
56
|
+
if (!user) throw new NotFoundError(`User '${input.id}' not found`);
|
|
57
|
+
return user;
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
@@ -18,13 +18,15 @@ import { createRouter, extractRoutes } from '@veloxts/velox';
|
|
|
18
18
|
|
|
19
19
|
import { authProcedures } from './procedures/auth.js';
|
|
20
20
|
import { healthProcedures } from './procedures/health.js';
|
|
21
|
+
import { profileProcedures } from './procedures/profiles.js';
|
|
21
22
|
import { userProcedures } from './procedures/users.js';
|
|
22
23
|
|
|
23
24
|
// Create router and collections from procedure definitions
|
|
24
25
|
export const { collections, router } = createRouter(
|
|
25
26
|
healthProcedures,
|
|
26
27
|
authProcedures,
|
|
27
|
-
userProcedures
|
|
28
|
+
userProcedures,
|
|
29
|
+
profileProcedures
|
|
28
30
|
);
|
|
29
31
|
|
|
30
32
|
export type AppRouter = typeof router;
|
|
@@ -34,4 +34,8 @@ export const routes: RouteMap = {
|
|
|
34
34
|
patchUser: { method: 'PATCH', path: '/users/:id', kind: 'mutation' },
|
|
35
35
|
deleteUser: { method: 'DELETE', path: '/users/:id', kind: 'mutation' },
|
|
36
36
|
},
|
|
37
|
+
profiles: {
|
|
38
|
+
getProfile: { method: 'GET', path: '/profiles/:id', kind: 'query' },
|
|
39
|
+
getFullProfile: { method: 'GET', path: '/profiles/:id/full', kind: 'query' },
|
|
40
|
+
},
|
|
37
41
|
};
|
|
@@ -15,11 +15,17 @@ import { createH3ApiHandler } from '@veloxts/web/adapters';
|
|
|
15
15
|
import { db } from './database.js';
|
|
16
16
|
import { authProcedures } from './procedures/auth.js';
|
|
17
17
|
import { healthProcedures } from './procedures/health.js';
|
|
18
|
+
import { profileProcedures } from './procedures/profiles.js';
|
|
18
19
|
import { userProcedures } from './procedures/users.js';
|
|
19
20
|
import { getJwtSecrets, parseUserRoles, tokenStore } from './utils/auth.js';
|
|
20
21
|
|
|
21
22
|
// Export router type for frontend type safety
|
|
22
|
-
const router = {
|
|
23
|
+
const router = {
|
|
24
|
+
health: healthProcedures,
|
|
25
|
+
users: userProcedures,
|
|
26
|
+
auth: authProcedures,
|
|
27
|
+
profiles: profileProcedures,
|
|
28
|
+
};
|
|
23
29
|
export type AppRouter = typeof router;
|
|
24
30
|
|
|
25
31
|
/**
|
|
@@ -74,7 +80,7 @@ export default createH3ApiHandler({
|
|
|
74
80
|
|
|
75
81
|
// Register REST routes from procedures
|
|
76
82
|
app.routes(
|
|
77
|
-
rest([healthProcedures, userProcedures, authProcedures], {
|
|
83
|
+
rest([healthProcedures, userProcedures, authProcedures, profileProcedures], {
|
|
78
84
|
prefix: '', // No prefix - Vinxi handles /api/*
|
|
79
85
|
})
|
|
80
86
|
);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile Procedures (Resource API Example)
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates field-level visibility using tagged resource schemas:
|
|
5
|
+
* - Public: GET /api/profiles/:id → { id, name }
|
|
6
|
+
* Uses handler-level projection: resource(data, Schema.public)
|
|
7
|
+
* - Authenticated: GET /api/profiles/:id/full → { id, name, email }
|
|
8
|
+
* Uses procedure-level auto-projection: .resource(Schema.authenticated)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { authenticatedNarrow } from '@veloxts/auth';
|
|
12
|
+
import { procedure, procedures, resource, resourceSchema } from '@veloxts/router';
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
|
|
15
|
+
import { db } from '../database.js';
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Resource Schema (field-level visibility)
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
const UserProfileSchema = resourceSchema()
|
|
22
|
+
.public('id', z.string().uuid())
|
|
23
|
+
.public('name', z.string())
|
|
24
|
+
.authenticated('email', z.string().email())
|
|
25
|
+
.build();
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Profile Procedures
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
export const profileProcedures = procedures('profiles', {
|
|
32
|
+
// Public: GET /api/profiles/:id → { id, name }
|
|
33
|
+
// Handler-level projection: resource(data, Schema.public) returns projected data directly
|
|
34
|
+
getProfile: procedure()
|
|
35
|
+
.input(z.object({ id: z.string().uuid() }))
|
|
36
|
+
.resource(UserProfileSchema.public)
|
|
37
|
+
.query(async ({ input }) => {
|
|
38
|
+
const user = await db.user.findUnique({ where: { id: input.id } });
|
|
39
|
+
if (!user) {
|
|
40
|
+
throw Object.assign(new Error('User not found'), { statusCode: 404 });
|
|
41
|
+
}
|
|
42
|
+
return resource(user, UserProfileSchema.public);
|
|
43
|
+
}),
|
|
44
|
+
|
|
45
|
+
// Authenticated: GET /api/profiles/:id/full → { id, name, email }
|
|
46
|
+
// Procedure-level auto-projection: .resource(Schema.authenticated) auto-projects the return value
|
|
47
|
+
getFullProfile: procedure()
|
|
48
|
+
.rest({ method: 'GET', path: '/profiles/:id/full' })
|
|
49
|
+
.guardNarrow(authenticatedNarrow)
|
|
50
|
+
.input(z.object({ id: z.string().uuid() }))
|
|
51
|
+
.resource(UserProfileSchema.authenticated)
|
|
52
|
+
.query(async ({ input }) => {
|
|
53
|
+
const user = await db.user.findUnique({ where: { id: input.id } });
|
|
54
|
+
if (!user) {
|
|
55
|
+
throw Object.assign(new Error('User not found'), { statusCode: 404 });
|
|
56
|
+
}
|
|
57
|
+
return user;
|
|
58
|
+
}),
|
|
59
|
+
});
|