Setup initial project
This commit is contained in:
commit
db79af06f7
119 changed files with 20761 additions and 0 deletions
81
packages/api/src/modules/users/users.routes.ts
Normal file
81
packages/api/src/modules/users/users.routes.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import fp from 'fastify-plugin';
|
||||
import { asClass, Lifetime } from 'awilix';
|
||||
import type { ZodTypeProvider } from 'fastify-type-provider-zod';
|
||||
import { z } from 'zod/v4';
|
||||
import { UsersRepository } from './users.repository.js';
|
||||
import { UsersService } from './users.service.js';
|
||||
import { NotFoundError } from '../../common/errors.js';
|
||||
|
||||
type AnyUserDoc = {
|
||||
_id: string | { toString: () => string };
|
||||
keycloakId: string;
|
||||
displayName: string;
|
||||
email: string;
|
||||
householdIds: string[];
|
||||
defaultHouseholdId?: string | null;
|
||||
createdAt: string | { toISOString: () => string };
|
||||
updatedAt: string | { toISOString: () => string };
|
||||
};
|
||||
|
||||
function toUserResponse(doc: AnyUserDoc) {
|
||||
const id = typeof doc._id === 'string' ? doc._id : doc._id.toString();
|
||||
const createdAt = typeof doc.createdAt === 'string' ? doc.createdAt : doc.createdAt.toISOString();
|
||||
const updatedAt = typeof doc.updatedAt === 'string' ? doc.updatedAt : doc.updatedAt.toISOString();
|
||||
return {
|
||||
_id: id,
|
||||
keycloakId: doc.keycloakId,
|
||||
displayName: doc.displayName,
|
||||
email: doc.email,
|
||||
householdIds: doc.householdIds,
|
||||
defaultHouseholdId: doc.defaultHouseholdId ?? null,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
declare module '@fastify/awilix' {
|
||||
interface Cradle {
|
||||
usersRepository: UsersRepository;
|
||||
usersService: UsersService;
|
||||
}
|
||||
}
|
||||
|
||||
export default fp(
|
||||
async (fastify) => {
|
||||
// Register DI
|
||||
fastify.diContainer.register({
|
||||
usersRepository: asClass(UsersRepository, { lifetime: Lifetime.SINGLETON }),
|
||||
usersService: asClass(UsersService, { lifetime: Lifetime.SINGLETON }),
|
||||
});
|
||||
|
||||
const app = fastify.withTypeProvider<ZodTypeProvider>();
|
||||
|
||||
// GET /api/v1/users/me — get current user profile (syncs from token on first call)
|
||||
app.route({
|
||||
method: 'GET',
|
||||
url: '/api/v1/users/me',
|
||||
config: { skipHousehold: true },
|
||||
schema: {
|
||||
response: {
|
||||
200: z.object({
|
||||
_id: z.string(),
|
||||
keycloakId: z.string(),
|
||||
displayName: z.string(),
|
||||
email: z.string(),
|
||||
householdIds: z.array(z.string()),
|
||||
defaultHouseholdId: z.string().nullable(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
handler: async (request, reply) => {
|
||||
const service = fastify.diContainer.resolve('usersService');
|
||||
const user = await service.syncFromToken(request.user);
|
||||
if (!user) throw new NotFoundError('User sync failed');
|
||||
return reply.send(toUserResponse(user));
|
||||
},
|
||||
});
|
||||
},
|
||||
{ name: 'users-routes', dependencies: ['auth-plugin'] },
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue