@stjoseph/prumo 0.0.6 → 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.
Files changed (139) hide show
  1. package/.prumo-templates/api/auth.md +51 -95
  2. package/.prumo-templates/api/config.md +30 -56
  3. package/.prumo-templates/api/errors.md +64 -44
  4. package/.prumo-templates/api/logging.md +27 -44
  5. package/.prumo-templates/api/observability.md +36 -62
  6. package/.prumo-templates/api/pagination.md +23 -38
  7. package/.prumo-templates/api/routes.md +67 -48
  8. package/.prumo-templates/api/structure.md +130 -0
  9. package/.prumo-templates/client/data.md +4 -3
  10. package/.prumo-templates/core/conventions.md +10 -7
  11. package/.prumo-templates/core/testing.md +43 -26
  12. package/.prumo-templates/core/tooling.md +33 -30
  13. package/.prumo-templates/database/entities.md +53 -61
  14. package/.prumo-templates/database/queries.md +34 -47
  15. package/.prumo-templates/database/transactions.md +28 -38
  16. package/.prumo-templates/mcp/server.md +54 -0
  17. package/.prumo-templates/monorepo/dependencies.md +3 -3
  18. package/.prumo-templates/monorepo/layout.md +1 -1
  19. package/README.md +6 -6
  20. package/dist/asker.js +4 -0
  21. package/dist/cli.js +4 -0
  22. package/dist/commands.js +2 -0
  23. package/dist/compose.js +6 -2
  24. package/dist/context.js +2 -0
  25. package/dist/generate.js +8 -0
  26. package/dist/mcp.js +100 -0
  27. package/dist/questions.js +21 -1
  28. package/package.json +4 -3
  29. package/templates/api/.swcrc +13 -0
  30. package/templates/api/biome.jsonc +5 -3
  31. package/templates/api/package.json +21 -27
  32. package/templates/api/pnpm-workspace.yaml +0 -2
  33. package/templates/api/src/domain/shared/errors/domain-error.ts +5 -0
  34. package/templates/api/src/domain/shared/transactions/transaction-manager.ts +5 -0
  35. package/templates/api/src/domain/users/dto/profile-response.dto.ts +14 -0
  36. package/templates/api/src/domain/users/dto/update-profile.dto.ts +10 -0
  37. package/templates/api/src/domain/users/entities/profile.entity.ts +26 -0
  38. package/templates/api/src/domain/users/errors/profile-not-found.error.ts +9 -0
  39. package/templates/api/src/domain/users/repositories/profile.repository.ts +8 -0
  40. package/templates/api/src/domain/users/use-cases/create-profile.use-case.ts +19 -0
  41. package/templates/api/src/domain/users/use-cases/find-profile.use-case.ts +22 -0
  42. package/templates/api/src/domain/users/use-cases/update-profile.use-case.ts +26 -0
  43. package/templates/api/src/infra/auth/auth.cli.ts +5 -0
  44. package/templates/api/src/{auth → infra/auth}/auth.factory.ts +26 -1
  45. package/templates/api/src/infra/config/env.ts +47 -0
  46. package/templates/api/src/infra/database/mikroorm/entities/auth-user.schema.ts +16 -0
  47. package/templates/api/src/infra/database/mikroorm/entities/profile.schema.ts +28 -0
  48. package/templates/api/src/{mikro-orm.config.ts → infra/database/mikroorm/mikro-orm.config.ts} +1 -1
  49. package/templates/api/src/infra/database/mikroorm/mikro-orm.factory.ts +17 -0
  50. package/templates/api/src/infra/database/mikroorm/repositories/mikroorm-profile.repository.ts +17 -0
  51. package/templates/api/src/infra/database/mikroorm/transactions/mikroorm-transaction-manager.ts +14 -0
  52. package/templates/api/src/infra/di/index.ts +32 -0
  53. package/templates/api/src/infra/di/users.di.ts +7 -0
  54. package/templates/api/src/infra/http/app.ts +99 -0
  55. package/templates/api/src/infra/http/controllers/auth.controller.ts +36 -0
  56. package/templates/api/src/infra/http/controllers/health.controller.ts +19 -0
  57. package/templates/api/src/infra/http/controllers/mcp.controller.ts +40 -0
  58. package/templates/api/src/infra/http/controllers/users.controller.ts +35 -0
  59. package/templates/api/src/infra/http/errors/error-handler.ts +116 -0
  60. package/templates/api/src/infra/http/errors/http-error.ts +8 -0
  61. package/templates/api/src/infra/http/fastify.d.ts +17 -0
  62. package/templates/api/src/infra/http/fetch-bridge.ts +42 -0
  63. package/templates/api/src/infra/http/hooks/auth.hook.ts +32 -0
  64. package/templates/api/src/infra/http/hooks/request-context.hook.ts +9 -0
  65. package/templates/api/src/infra/http/server.ts +34 -0
  66. package/templates/api/src/infra/mcp/mcp.server.ts +20 -0
  67. package/templates/api/src/infra/mcp/tools/users.tool.ts +39 -0
  68. package/templates/api/test/domain/users/use-cases/find-profile.use-case.spec.ts +22 -0
  69. package/templates/api/test/domain/users/use-cases/update-profile.use-case.spec.ts +26 -0
  70. package/templates/api/{src → test/infra}/auth/auth.factory.spec.ts +4 -11
  71. package/templates/api/test/infra/database/mikroorm/mikro-orm.factory.spec.ts +8 -0
  72. package/templates/api/test/infra/database/mikroorm/repositories/mikroorm-profile.repository.spec.ts +51 -0
  73. package/templates/api/test/infra/database/mikroorm/transactions/mikroorm-transaction-manager.spec.ts +29 -0
  74. package/templates/api/test/infra/http/app.spec.ts +21 -0
  75. package/templates/api/test/infra/http/controllers/mcp.controller.spec.ts +152 -0
  76. package/templates/api/test/infra/http/controllers/users.controller.spec.ts +105 -0
  77. package/templates/api/test/support/factories/profile.factory.ts +25 -0
  78. package/templates/api/test/{factories → support/factories}/user.factory.ts +1 -1
  79. package/templates/api/test/support/fakes/in-memory-profile.repository.ts +14 -0
  80. package/templates/api/test/{setup.ts → support/setup.ts} +26 -14
  81. package/templates/api/tsconfig.json +3 -6
  82. package/templates/api/vitest.config.mts +4 -4
  83. package/templates/mobile/jest.config.js +1 -1
  84. package/templates/mobile/package.json +2 -2
  85. package/templates/mobile/{src → test}/features/auth/authenticated-layout.spec.tsx +1 -1
  86. package/templates/mobile/{src → test}/features/auth/sign-in-form.spec.tsx +2 -2
  87. package/templates/mobile/{src → test}/features/auth/sign-out-button.spec.tsx +2 -2
  88. package/templates/mobile/{src → test}/features/profile/profile-form.spec.tsx +2 -2
  89. package/templates/mobile/tsconfig.json +2 -1
  90. package/templates/site/{src → test}/app/page.spec.ts +1 -1
  91. package/templates/site/tsconfig.json +2 -1
  92. package/templates/site/vitest.config.mts +4 -2
  93. package/templates/web/package.json +4 -2
  94. package/templates/web/src/features/auth/auth-client.ts +5 -0
  95. package/templates/web/src/features/auth/sign-in-form.tsx +10 -3
  96. package/templates/web/src/features/oauth/consent-form.tsx +63 -0
  97. package/templates/web/src/routeTree.gen.ts +21 -2
  98. package/templates/web/src/routes/_authenticated/consent.tsx +21 -0
  99. package/templates/web/{src → test}/app.spec.tsx +2 -2
  100. package/templates/web/{src → test}/features/auth/sign-in-form.spec.tsx +2 -2
  101. package/templates/web/test/features/oauth/consent-form.spec.tsx +45 -0
  102. package/templates/web/{src → test}/features/profile/profile-form.spec.tsx +2 -2
  103. package/templates/web/test/{render-app.tsx → support/render-app.tsx} +1 -1
  104. package/templates/web/tsconfig.json +2 -1
  105. package/templates/web/vite.config.ts +3 -3
  106. package/.prumo-templates/api/modules.md +0 -117
  107. package/templates/api/nest-cli.json +0 -10
  108. package/templates/api/src/app.module.ts +0 -46
  109. package/templates/api/src/auth/auth.constants.ts +0 -2
  110. package/templates/api/src/auth/auth.controller.ts +0 -19
  111. package/templates/api/src/auth/auth.guard.ts +0 -43
  112. package/templates/api/src/auth/auth.module.ts +0 -30
  113. package/templates/api/src/auth/auth.ts +0 -4
  114. package/templates/api/src/auth/current-user.decorator.ts +0 -9
  115. package/templates/api/src/auth/express.d.ts +0 -10
  116. package/templates/api/src/auth/public.decorator.ts +0 -4
  117. package/templates/api/src/config/env.module.ts +0 -11
  118. package/templates/api/src/config/env.ts +0 -81
  119. package/templates/api/src/errors/problem-details.filter.ts +0 -86
  120. package/templates/api/src/errors/validation-exception.factory.ts +0 -30
  121. package/templates/api/src/health/health.controller.ts +0 -32
  122. package/templates/api/src/health/health.module.ts +0 -9
  123. package/templates/api/src/main.ts +0 -43
  124. package/templates/api/src/mikro-orm.factory.ts +0 -14
  125. package/templates/api/src/request-context/request-context.module.ts +0 -9
  126. package/templates/api/src/request-context/request-context.service.ts +0 -17
  127. package/templates/api/src/request-context/request-id.middleware.ts +0 -19
  128. package/templates/api/src/users/dto/update-profile.dto.ts +0 -20
  129. package/templates/api/src/users/entities/profile.entity.ts +0 -27
  130. package/templates/api/src/users/users.controller.ts +0 -23
  131. package/templates/api/src/users/users.module.ts +0 -10
  132. package/templates/api/src/users/users.service.spec.ts +0 -44
  133. package/templates/api/src/users/users.service.ts +0 -36
  134. package/templates/api/test/factories/profile.factory.ts +0 -26
  135. package/templates/api/tsconfig.build.json +0 -8
  136. /package/templates/api/test/{global-setup.ts → support/global-setup.ts} +0 -0
  137. /package/templates/mobile/test/{fake-transport.ts → support/fake-transport.ts} +0 -0
  138. /package/templates/web/test/{fake-transport.ts → support/fake-transport.ts} +0 -0
  139. /package/templates/web/test/{setup.ts → support/setup.ts} +0 -0
@@ -1,19 +0,0 @@
1
- import { randomUUID } from 'node:crypto'
2
- import { Injectable, type NestMiddleware } from '@nestjs/common'
3
- import type { NextFunction, Request, Response } from 'express'
4
- import { RequestContextService } from './request-context.service'
5
-
6
- export const REQUEST_ID_HEADER = 'x-request-id'
7
-
8
- @Injectable()
9
- export class RequestIdMiddleware implements NestMiddleware {
10
- constructor(private readonly context: RequestContextService) {}
11
-
12
- use(request: Request, response: Response, next: NextFunction): void {
13
- const inbound = request.header(REQUEST_ID_HEADER)
14
- const requestId = inbound && inbound.length > 0 ? inbound : randomUUID()
15
-
16
- response.setHeader(REQUEST_ID_HEADER, requestId)
17
- this.context.run(requestId, next)
18
- }
19
- }
@@ -1,20 +0,0 @@
1
- import { IsIn, IsOptional, IsString, MaxLength, MinLength } from 'class-validator'
2
-
3
- const LOCALES = ['en', 'pt-BR'] as const
4
-
5
- export class UpdateProfileDto {
6
- @IsOptional()
7
- @IsString()
8
- @MinLength(1)
9
- @MaxLength(80)
10
- displayName?: string
11
-
12
- @IsOptional()
13
- @IsIn(LOCALES)
14
- locale?: (typeof LOCALES)[number]
15
-
16
- @IsOptional()
17
- @IsString()
18
- @MaxLength(64)
19
- timezone?: string
20
- }
@@ -1,27 +0,0 @@
1
- import { defineEntity, p } from '@mikro-orm/core'
2
-
3
- const ProfileSchema = defineEntity({
4
- name: 'Profile',
5
- properties: {
6
- id: p.uuid().primary().defaultRaw('uuidv7()'),
7
- userId: p.uuid().unique(),
8
- displayName: p.text(),
9
- locale: p.text().default('en'),
10
- timezone: p.text().default('UTC'),
11
- createdAt: p
12
- .datetime()
13
- .onCreate(() => new Date())
14
- .defaultRaw('now()'),
15
- updatedAt: p
16
- .datetime()
17
- .onCreate(() => new Date())
18
- .onUpdate(() => new Date())
19
- .defaultRaw('now()'),
20
- },
21
- })
22
-
23
- export class Profile extends ProfileSchema.class {}
24
-
25
- ProfileSchema.setClass(Profile)
26
-
27
- export { ProfileSchema }
@@ -1,23 +0,0 @@
1
- import { Body, Controller, Get, Patch } from '@nestjs/common'
2
- import { ApiTags } from '@nestjs/swagger'
3
- import type { AuthUser } from '@/auth/auth.factory'
4
- import { CurrentUser } from '@/auth/current-user.decorator'
5
- import { UpdateProfileDto } from './dto/update-profile.dto'
6
- import type { Profile } from './entities/profile.entity'
7
- import { UsersService } from './users.service'
8
-
9
- @ApiTags('users')
10
- @Controller({ path: 'users', version: '1' })
11
- export class UsersController {
12
- constructor(private readonly users: UsersService) {}
13
-
14
- @Get('me')
15
- findMe(@CurrentUser() user: AuthUser): Promise<Profile> {
16
- return this.users.findProfile(user.id)
17
- }
18
-
19
- @Patch('me')
20
- updateMe(@CurrentUser() user: AuthUser, @Body() changes: UpdateProfileDto): Promise<Profile> {
21
- return this.users.updateProfile(user.id, changes)
22
- }
23
- }
@@ -1,10 +0,0 @@
1
- import { Module } from '@nestjs/common'
2
- import { UsersController } from './users.controller'
3
- import { UsersService } from './users.service'
4
-
5
- @Module({
6
- controllers: [UsersController],
7
- providers: [UsersService],
8
- exports: [UsersService],
9
- })
10
- export class UsersModule {}
@@ -1,44 +0,0 @@
1
- import { NotFoundException } from '@nestjs/common'
2
- import { plainToInstance } from 'class-transformer'
3
- import { beforeEach, describe, expect, it } from 'vitest'
4
- import { createProfile } from '../../test/factories/profile.factory'
5
- import { testOrm } from '../../test/setup'
6
- import { UpdateProfileDto } from './dto/update-profile.dto'
7
- import { UsersService } from './users.service'
8
-
9
- describe('UsersService', () => {
10
- let service: UsersService
11
-
12
- beforeEach(() => {
13
- service = new UsersService(testOrm().em.fork())
14
- })
15
-
16
- it('finds the profile belonging to a user', async () => {
17
- const em = testOrm().em.fork()
18
- const created = await createProfile(em, { displayName: 'Ana' })
19
-
20
- await expect(service.findProfile(created.userId)).resolves.toMatchObject({
21
- displayName: 'Ana',
22
- })
23
- })
24
-
25
- it('refuses a user without a profile', async () => {
26
- await expect(service.findProfile(crypto.randomUUID())).rejects.toBeInstanceOf(NotFoundException)
27
- })
28
-
29
- it('applies only the fields the request carries', async () => {
30
- const em = testOrm().em.fork()
31
- const created = await createProfile(em, {
32
- displayName: 'Ana',
33
- timezone: 'UTC',
34
- })
35
-
36
- const changes = plainToInstance(UpdateProfileDto, { timezone: 'America/Sao_Paulo' })
37
- const updated = await service.updateProfile(created.userId, changes)
38
-
39
- expect(updated).toMatchObject({
40
- displayName: 'Ana',
41
- timezone: 'America/Sao_Paulo',
42
- })
43
- })
44
- })
@@ -1,36 +0,0 @@
1
- import { EntityManager } from '@mikro-orm/postgresql'
2
- import { Injectable, NotFoundException } from '@nestjs/common'
3
- import type { UpdateProfileDto } from './dto/update-profile.dto'
4
- import { Profile } from './entities/profile.entity'
5
-
6
- @Injectable()
7
- export class UsersService {
8
- constructor(private readonly em: EntityManager) {}
9
-
10
- async findProfile(userId: string): Promise<Profile> {
11
- const profile = await this.em.findOne(Profile, { userId })
12
-
13
- if (profile === null) {
14
- throw new NotFoundException('Profile not found')
15
- }
16
-
17
- return profile
18
- }
19
-
20
- async updateProfile(userId: string, changes: UpdateProfileDto): Promise<Profile> {
21
- const profile = await this.findProfile(userId)
22
-
23
- this.em.assign(profile, changes, { ignoreUndefined: true })
24
- await this.em.flush()
25
-
26
- return profile
27
- }
28
-
29
- async createProfile(userId: string, displayName: string): Promise<Profile> {
30
- const profile = this.em.create(Profile, { userId, displayName })
31
-
32
- await this.em.flush()
33
-
34
- return profile
35
- }
36
- }
@@ -1,26 +0,0 @@
1
- import type { EntityManager } from '@mikro-orm/postgresql'
2
- import { Profile } from '@/users/entities/profile.entity'
3
- import { createUser } from './user.factory'
4
-
5
- type ProfileOverrides = Partial<{
6
- userId: string
7
- displayName: string
8
- locale: string
9
- timezone: string
10
- }>
11
-
12
- export async function createProfile(
13
- em: EntityManager,
14
- overrides: ProfileOverrides = {},
15
- ): Promise<Profile> {
16
- const profile = em.create(Profile, {
17
- userId: overrides.userId ?? (await createUser(em)),
18
- displayName: overrides.displayName ?? 'Test Person',
19
- locale: overrides.locale ?? 'en',
20
- timezone: overrides.timezone ?? 'UTC',
21
- })
22
-
23
- await em.flush()
24
-
25
- return profile
26
- }
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "./src"
5
- },
6
- "include": ["src"],
7
- "exclude": ["node_modules", "dist", "test", "**/*.spec.ts"]
8
- }