├── .nyc_output ├── defb6e19-9ca1-4ca5-a859-ac8b8387cd53.json ├── processinfo │ ├── defb6e19-9ca1-4ca5-a859-ac8b8387cd53.json │ ├── 46549699-3d4c-40cc-b68f-7a5d8d57f54e.json │ ├── c5d44f9d-91ad-40f6-92f4-9e215e65e6d1.json │ ├── 2ed0c525-4275-4d6b-9366-c389109cc42b.json │ └── index.json ├── 2ed0c525-4275-4d6b-9366-c389109cc42b.json └── 46549699-3d4c-40cc-b68f-7a5d8d57f54e.json ├── .gitignore ├── src ├── utils │ ├── prisma.ts │ └── hash.ts ├── app.ts ├── __test__ │ └── server.test.ts ├── modules │ ├── product │ │ ├── product.controller.ts │ │ ├── product.service.ts │ │ ├── product.route.ts │ │ └── product.schema.ts │ └── user │ │ ├── user.service.ts │ │ ├── user.route.ts │ │ ├── user.schema.ts │ │ ├── user.controller.ts │ │ └── __test__ │ │ ├── login.test.ts │ │ └── registerUser.test.ts └── server.ts ├── prisma ├── migrations │ ├── migration_lock.toml │ ├── 20220225101506_init │ │ └── migration.sql │ └── 20220225090420_init │ │ └── migration.sql └── schema.prisma ├── NOTES.md ├── .env.test ├── package.json ├── Fastify Prisma Tutorial.postman_environment.json ├── README.md ├── Fastify Prisma Tutorial.postman_collection.json └── tsconfig.json /.nyc_output/defb6e19-9ca1-4ca5-a859-ac8b8387cd53.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | # Keep environment variables out of version control 3 | .env 4 | -------------------------------------------------------------------------------- /src/utils/prisma.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | const prisma = new PrismaClient(); 4 | 5 | export default prisma; 6 | -------------------------------------------------------------------------------- /prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /prisma/migrations/20220225101506_init/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `createAt` on the `Product` table. All the data in the column will be lost. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "Product" DROP COLUMN "createAt", 9 | ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; 10 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import buildServer from "./server"; 2 | 3 | const server = buildServer(); 4 | 5 | async function main() { 6 | try { 7 | await server.listen(3000, "0.0.0.0"); 8 | 9 | console.log(`Server ready at http://localhost:3000`); 10 | } catch (e) { 11 | console.error(e); 12 | process.exit(1); 13 | } 14 | } 15 | 16 | main(); 17 | -------------------------------------------------------------------------------- /NOTES.md: -------------------------------------------------------------------------------- 1 | ## dependencies 2 | yarn add @prisma/client fastify fastify-zod zod zod-to-json-schema fastify-jwt fastify-swagger 3 | 4 | ## devDependencies 5 | yarn add ts-node-dev typescript @types/node --dev 6 | 7 | ## Initialise prisma 8 | npx prisma init --datasource-provider postgresql 9 | 10 | ### Migrate the schema 11 | npx prisma migrate dev --name init -------------------------------------------------------------------------------- /src/__test__/server.test.ts: -------------------------------------------------------------------------------- 1 | import { test } from "tap"; 2 | import buildServer from "../server"; 3 | 4 | test("requests the `/healthcheck` route", async (t) => { 5 | const fastify = buildServer(); 6 | 7 | t.teardown(() => { 8 | fastify.close(); 9 | }); 10 | 11 | const response = await fastify.inject({ 12 | method: "GET", 13 | url: "/healthcheck", 14 | }); 15 | 16 | t.equal(response.statusCode, 200); 17 | t.same(response.json(), { status: "OK" }); 18 | }); 19 | -------------------------------------------------------------------------------- /.nyc_output/processinfo/defb6e19-9ca1-4ca5-a859-ac8b8387cd53.json: -------------------------------------------------------------------------------- 1 | {"parent":null,"pid":406,"argv":["/Users/tom/.nvm/versions/node/v14.18.1/bin/node","/Users/tom/projects/fastify-prisma/node_modules/tap/bin/run.js","--node-arg=--require=ts-node/register","--watch","--no-watch"],"execArgv":[],"cwd":"/Users/tom/projects/fastify-prisma","time":1647167270755,"ppid":405,"coverageFilename":"/Users/tom/projects/fastify-prisma/.nyc_output/defb6e19-9ca1-4ca5-a859-ac8b8387cd53.json","externalId":"","uuid":"defb6e19-9ca1-4ca5-a859-ac8b8387cd53","files":[]} -------------------------------------------------------------------------------- /.env.test: -------------------------------------------------------------------------------- 1 | # Environment variables declared in this file are automatically made available to Prisma. 2 | # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema 3 | 4 | # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB (Preview) and CockroachDB (Preview). 5 | # See the documentation for all the connection string options: https://pris.ly/d/connection-strings 6 | 7 | DATABASE_URL="postgresql://postgres:changeme@localhost:5432/test-database?schema=public" -------------------------------------------------------------------------------- /src/modules/product/product.controller.ts: -------------------------------------------------------------------------------- 1 | import { FastifyReply, FastifyRequest } from "fastify"; 2 | import { CreateProductInput } from "./product.schema"; 3 | import { createProduct, getProducts } from "./product.service"; 4 | 5 | export async function createProductHandler( 6 | request: FastifyRequest<{ 7 | Body: CreateProductInput; 8 | }> 9 | ) { 10 | const product = await createProduct({ 11 | ...request.body, 12 | ownerId: request.user.id, 13 | }); 14 | 15 | return product; 16 | } 17 | 18 | export async function getProductsHandler() { 19 | const products = await getProducts(); 20 | 21 | return products; 22 | } 23 | -------------------------------------------------------------------------------- /src/modules/product/product.service.ts: -------------------------------------------------------------------------------- 1 | import prisma from "../../utils/prisma"; 2 | import { CreateProductInput } from "./product.schema"; 3 | 4 | export async function createProduct( 5 | data: CreateProductInput & { ownerId: number } 6 | ) { 7 | return prisma.product.create({ 8 | data, 9 | }); 10 | } 11 | 12 | export function getProducts() { 13 | return prisma.product.findMany({ 14 | select: { 15 | content: true, 16 | title: true, 17 | price: true, 18 | id: true, 19 | createdAt: true, 20 | updatedAt: true, 21 | owner: { 22 | select: { 23 | name: true, 24 | id: true, 25 | }, 26 | }, 27 | }, 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | } 7 | 8 | datasource db { 9 | provider = "postgresql" 10 | url = env("DATABASE_URL") 11 | } 12 | 13 | 14 | model User { 15 | id Int @id @default(autoincrement()) 16 | email String @unique 17 | name String? 18 | password String 19 | salt String 20 | products Product[] 21 | } 22 | 23 | model Product { 24 | id Int @id @default(autoincrement()) 25 | createdAt DateTime @default(now()) 26 | updatedAt DateTime @updatedAt 27 | title String @db.VarChar(255) 28 | content String? 29 | price Float 30 | owner User @relation(fields: [ownerId], references: [id]) 31 | ownerId Int 32 | } -------------------------------------------------------------------------------- /src/modules/user/user.service.ts: -------------------------------------------------------------------------------- 1 | import { hashPassword } from "../../utils/hash"; 2 | import prisma from "../../utils/prisma"; 3 | import { CreateUserInput } from "./user.schema"; 4 | 5 | export async function createUser(input: CreateUserInput) { 6 | const { password, ...rest } = input; 7 | 8 | const { hash, salt } = hashPassword(password); 9 | 10 | const user = await prisma.user.create({ 11 | data: { ...rest, salt, password: hash }, 12 | }); 13 | 14 | return user; 15 | } 16 | 17 | export async function findUserByEmail(email: string) { 18 | return prisma.user.findUnique({ 19 | where: { 20 | email, 21 | }, 22 | }); 23 | } 24 | 25 | export async function findUsers() { 26 | return prisma.user.findMany({ 27 | select: { 28 | email: true, 29 | name: true, 30 | id: true, 31 | }, 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /src/modules/product/product.route.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance } from "fastify"; 2 | import { createProductHandler, getProductsHandler } from "./product.controller"; 3 | import { $ref } from "./product.schema"; 4 | 5 | async function productRoutes(server: FastifyInstance) { 6 | server.post( 7 | "/", 8 | { 9 | preHandler: [server.authenticate], 10 | schema: { 11 | body: $ref("createProductSchema"), 12 | response: { 13 | 201: $ref("productResponseSchema"), 14 | }, 15 | }, 16 | }, 17 | createProductHandler 18 | ); 19 | 20 | server.get( 21 | "/", 22 | { 23 | schema: { 24 | response: { 25 | 200: $ref("productsResponseSchema"), 26 | }, 27 | }, 28 | }, 29 | 30 | getProductsHandler 31 | ); 32 | } 33 | 34 | export default productRoutes; 35 | -------------------------------------------------------------------------------- /src/modules/product/product.schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { buildJsonSchemas } from "fastify-zod"; 3 | 4 | const productInput = { 5 | title: z.string(), 6 | price: z.number(), 7 | content: z.string().optional(), 8 | }; 9 | 10 | const productGenerated = { 11 | id: z.number(), 12 | createdAt: z.string(), 13 | updatedAt: z.string(), 14 | }; 15 | 16 | const createProductSchema = z.object({ 17 | ...productInput, 18 | }); 19 | 20 | const productResponseSchema = z.object({ 21 | ...productInput, 22 | ...productGenerated, 23 | }); 24 | 25 | const productsResponseSchema = z.array(productResponseSchema); 26 | 27 | export type CreateProductInput = z.infer; 28 | 29 | export const { schemas: productSchemas, $ref } = buildJsonSchemas({ 30 | createProductSchema, 31 | productResponseSchema, 32 | productsResponseSchema, 33 | }); 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fastify-prisma", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "Tom Nagle", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "tsnd --respawn --transpile-only --exit-child src/app.ts", 9 | "test": "tap --node-arg=--require=ts-node/register" 10 | }, 11 | "dependencies": { 12 | "@faker-js/faker": "^6.0.0-beta.0", 13 | "@prisma/client": "^3.10.0", 14 | "fastify": "^3.27.2", 15 | "fastify-jwt": "^4.1.3", 16 | "fastify-swagger": "^4.15.0", 17 | "fastify-zod": "^0.0.2", 18 | "tap": "^16.0.0", 19 | "ts-mock-imports": "^1.3.8", 20 | "zod": "^3.12.0", 21 | "zod-to-json-schema": "^3.11.3" 22 | }, 23 | "devDependencies": { 24 | "@types/node": "^17.0.21", 25 | "@types/tap": "^15.0.6", 26 | "sinon": "^13.0.1", 27 | "ts-node": "^10.7.0", 28 | "ts-node-dev": "^1.1.8", 29 | "typescript": "^4.5.5" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /prisma/migrations/20220225090420_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "User" ( 3 | "id" SERIAL NOT NULL, 4 | "email" TEXT NOT NULL, 5 | "name" TEXT, 6 | "password" TEXT NOT NULL, 7 | "salt" TEXT NOT NULL, 8 | 9 | CONSTRAINT "User_pkey" PRIMARY KEY ("id") 10 | ); 11 | 12 | -- CreateTable 13 | CREATE TABLE "Product" ( 14 | "id" SERIAL NOT NULL, 15 | "createAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 16 | "updatedAt" TIMESTAMP(3) NOT NULL, 17 | "title" VARCHAR(255) NOT NULL, 18 | "content" TEXT, 19 | "price" DOUBLE PRECISION NOT NULL, 20 | "ownerId" INTEGER NOT NULL, 21 | 22 | CONSTRAINT "Product_pkey" PRIMARY KEY ("id") 23 | ); 24 | 25 | -- CreateIndex 26 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); 27 | 28 | -- AddForeignKey 29 | ALTER TABLE "Product" ADD CONSTRAINT "Product_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 30 | -------------------------------------------------------------------------------- /src/modules/user/user.route.ts: -------------------------------------------------------------------------------- 1 | import { FastifyInstance } from "fastify"; 2 | import { 3 | loginHandler, 4 | registerUserHandler, 5 | getUsersHandler, 6 | } from "./user.controller"; 7 | import { $ref } from "./user.schema"; 8 | 9 | async function userRoutes(server: FastifyInstance) { 10 | server.post( 11 | "/", 12 | { 13 | schema: { 14 | body: $ref("createUserSchema"), 15 | response: { 16 | 201: $ref("createUserResponseSchema"), 17 | }, 18 | }, 19 | }, 20 | registerUserHandler 21 | ); 22 | 23 | server.post( 24 | "/login", 25 | { 26 | schema: { 27 | body: $ref("loginSchema"), 28 | response: { 29 | 200: $ref("loginResponseSchema"), 30 | }, 31 | }, 32 | }, 33 | loginHandler 34 | ); 35 | 36 | server.get( 37 | "/", 38 | { 39 | preHandler: [server.authenticate], 40 | }, 41 | getUsersHandler 42 | ); 43 | } 44 | 45 | export default userRoutes; 46 | -------------------------------------------------------------------------------- /Fastify Prisma Tutorial.postman_environment.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "8cd9bdf6-73db-41e7-8936-551e581d4cf4", 3 | "name": "Fastify Prisma Tutorial", 4 | "values": [ 5 | { 6 | "key": "host", 7 | "value": "http://localhost:3000", 8 | "type": "default", 9 | "enabled": true 10 | }, 11 | { 12 | "key": "email", 13 | "value": "", 14 | "type": "default", 15 | "enabled": true 16 | }, 17 | { 18 | "key": "name", 19 | "value": "", 20 | "type": "default", 21 | "enabled": true 22 | }, 23 | { 24 | "key": "password", 25 | "value": "", 26 | "type": "default", 27 | "enabled": true 28 | }, 29 | { 30 | "key": "accessToken", 31 | "value": "", 32 | "type": "any", 33 | "enabled": true 34 | }, 35 | { 36 | "key": "refreshToken", 37 | "value": "", 38 | "type": "any", 39 | "enabled": true 40 | } 41 | ], 42 | "_postman_variable_scope": "environment", 43 | "_postman_exported_at": "2022-02-25T07:05:44.415Z", 44 | "_postman_exported_using": "Postman/9.13.2" 45 | } -------------------------------------------------------------------------------- /src/utils/hash.ts: -------------------------------------------------------------------------------- 1 | import crypto from "crypto"; 2 | 3 | export function hashPassword(password: string) { 4 | /* 5 | * Creating a unique salt for a particular user 6 | * Salt is a random bit of data added to the user's password 7 | * Salt means that every password's hash is going to be unique 8 | */ 9 | const salt = crypto.randomBytes(16).toString("hex"); 10 | 11 | /* 12 | * Create a hash with 1000 iterations 13 | */ 14 | const hash = crypto 15 | .pbkdf2Sync(password, salt, 1000, 64, "sha512") 16 | .toString("hex"); 17 | 18 | return { hash, salt }; 19 | } 20 | 21 | export function verifyPassword({ 22 | candidatePassword, 23 | salt, 24 | hash, 25 | }: { 26 | candidatePassword: string; 27 | salt: string; 28 | hash: string; 29 | }) { 30 | /* 31 | * Create a hash with the salt from the user and the password 32 | * the user tried to login with 33 | */ 34 | const candidateHash = crypto 35 | .pbkdf2Sync(candidatePassword, salt, 1000, 64, "sha512") 36 | .toString("hex"); 37 | 38 | /* 39 | * If the hash matches the hash we have stored for the user 40 | * then the candidate password is correct 41 | */ 42 | 43 | return candidateHash === hash; 44 | } 45 | -------------------------------------------------------------------------------- /.nyc_output/processinfo/46549699-3d4c-40cc-b68f-7a5d8d57f54e.json: -------------------------------------------------------------------------------- 1 | {"parent":"defb6e19-9ca1-4ca5-a859-ac8b8387cd53","pid":411,"argv":["/Users/tom/.nvm/versions/node/v14.18.1/bin/node","/Users/tom/projects/fastify-prisma/src/__test__/server.test.ts"],"execArgv":["--require=ts-node/register"],"cwd":"/Users/tom/projects/fastify-prisma","time":1647167271301,"ppid":406,"coverageFilename":"/Users/tom/projects/fastify-prisma/.nyc_output/46549699-3d4c-40cc-b68f-7a5d8d57f54e.json","externalId":"src/__test__/server.test.ts","uuid":"46549699-3d4c-40cc-b68f-7a5d8d57f54e","files":["/Users/tom/projects/fastify-prisma/src/server.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts","/Users/tom/projects/fastify-prisma/src/utils/hash.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts","/Users/tom/projects/fastify-prisma/src/utils/prisma.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts"]} -------------------------------------------------------------------------------- /.nyc_output/processinfo/c5d44f9d-91ad-40f6-92f4-9e215e65e6d1.json: -------------------------------------------------------------------------------- 1 | {"parent":"defb6e19-9ca1-4ca5-a859-ac8b8387cd53","pid":409,"argv":["/Users/tom/.nvm/versions/node/v14.18.1/bin/node","/Users/tom/projects/fastify-prisma/src/modules/user/__test__/login.test.ts"],"execArgv":["--require=ts-node/register"],"cwd":"/Users/tom/projects/fastify-prisma","time":1647167271287,"ppid":406,"coverageFilename":"/Users/tom/projects/fastify-prisma/.nyc_output/c5d44f9d-91ad-40f6-92f4-9e215e65e6d1.json","externalId":"src/modules/user/__test__/login.test.ts","uuid":"c5d44f9d-91ad-40f6-92f4-9e215e65e6d1","files":["/Users/tom/projects/fastify-prisma/src/utils/prisma.ts","/Users/tom/projects/fastify-prisma/src/server.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts","/Users/tom/projects/fastify-prisma/src/utils/hash.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts"]} -------------------------------------------------------------------------------- /src/modules/user/user.schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { buildJsonSchemas } from "fastify-zod"; 3 | 4 | const userCore = { 5 | email: z 6 | .string({ 7 | required_error: "Email is required", 8 | invalid_type_error: "Email must be a string", 9 | }) 10 | .email(), 11 | name: z.string(), 12 | }; 13 | 14 | const createUserSchema = z.object({ 15 | ...userCore, 16 | password: z.string({ 17 | required_error: "Password is required", 18 | invalid_type_error: "Password must be a string", 19 | }), 20 | }); 21 | 22 | const createUserResponseSchema = z.object({ 23 | id: z.number(), 24 | ...userCore, 25 | }); 26 | 27 | const loginSchema = z.object({ 28 | email: z 29 | .string({ 30 | required_error: "Email is required", 31 | invalid_type_error: "Email must be a string", 32 | }) 33 | .email(), 34 | password: z.string(), 35 | }); 36 | 37 | const loginResponseSchema = z.object({ 38 | accessToken: z.string(), 39 | }); 40 | 41 | export type CreateUserInput = z.infer; 42 | 43 | export type LoginInput = z.infer; 44 | 45 | export const { schemas: userSchemas, $ref } = buildJsonSchemas({ 46 | createUserSchema, 47 | createUserResponseSchema, 48 | loginSchema, 49 | loginResponseSchema, 50 | }); 51 | -------------------------------------------------------------------------------- /.nyc_output/processinfo/2ed0c525-4275-4d6b-9366-c389109cc42b.json: -------------------------------------------------------------------------------- 1 | {"parent":"defb6e19-9ca1-4ca5-a859-ac8b8387cd53","pid":410,"argv":["/Users/tom/.nvm/versions/node/v14.18.1/bin/node","/Users/tom/projects/fastify-prisma/src/modules/user/__test__/registerUser.test.ts"],"execArgv":["--require=ts-node/register"],"cwd":"/Users/tom/projects/fastify-prisma","time":1647167271294,"ppid":406,"coverageFilename":"/Users/tom/projects/fastify-prisma/.nyc_output/2ed0c525-4275-4d6b-9366-c389109cc42b.json","externalId":"src/modules/user/__test__/registerUser.test.ts","uuid":"2ed0c525-4275-4d6b-9366-c389109cc42b","files":["/Users/tom/projects/fastify-prisma/src/server.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts","/Users/tom/projects/fastify-prisma/src/utils/hash.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts","/Users/tom/projects/fastify-prisma/src/utils/prisma.ts","/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts","/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts"]} -------------------------------------------------------------------------------- /src/modules/user/user.controller.ts: -------------------------------------------------------------------------------- 1 | import { FastifyReply, FastifyRequest } from "fastify"; 2 | import { verifyPassword } from "../../utils/hash"; 3 | import { CreateUserInput, LoginInput } from "./user.schema"; 4 | import { createUser, findUserByEmail, findUsers } from "./user.service"; 5 | 6 | export async function registerUserHandler( 7 | request: FastifyRequest<{ 8 | Body: CreateUserInput; 9 | }>, 10 | reply: FastifyReply 11 | ) { 12 | const body = request.body; 13 | 14 | try { 15 | const user = await createUser(body); 16 | 17 | return reply.code(201).send(user); 18 | } catch (e) { 19 | console.log(e); 20 | return reply.code(500).send(e); 21 | } 22 | } 23 | 24 | export async function loginHandler( 25 | request: FastifyRequest<{ 26 | Body: LoginInput; 27 | }>, 28 | reply: FastifyReply 29 | ) { 30 | const body = request.body; 31 | 32 | // find a user by email 33 | const user = await findUserByEmail(body.email); 34 | 35 | if (!user) { 36 | return reply.code(401).send({ 37 | message: "Invalid email or password", 38 | }); 39 | } 40 | 41 | // verify password 42 | const correctPassword = verifyPassword({ 43 | candidatePassword: body.password, 44 | salt: user.salt, 45 | hash: user.password, 46 | }); 47 | 48 | if (correctPassword) { 49 | const { password, salt, ...rest } = user; 50 | // generate access token 51 | return { accessToken: request.jwt.sign(rest) }; 52 | } 53 | 54 | return reply.code(401).send({ 55 | message: "Invalid email or password", 56 | }); 57 | } 58 | 59 | export async function getUsersHandler() { 60 | const users = await findUsers(); 61 | 62 | return users; 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Build a REST API with Fastify & Prisma 2 | 3 | Video: https://youtu.be/LMoMHP44-xM 4 | 5 | ## What are we using? 6 | * Fastify - Web server 7 | * Prisma - Database ORM 8 | * Zod - Request and response validation 9 | * Swagger - API docs 10 | * TypeScript - Types & other cool stuff 11 | 12 | ## What you will need 13 | * [Postman](https://www.postman.com/) - Make API requests 14 | * [Prisma studio](https://www.prisma.io/studio) - View data 15 | * [PostreSQL or MySQL](https://github.com/tomanagle/awesome-docker-compose) - Database 16 | * [Code editor](https://code.visualstudio.com/) - Edit your code 17 | 18 | ## Features 19 | * Create a user 20 | * Login 21 | * List users 22 | * Create a product 23 | * List products 24 | * Authentication 25 | * Request & response validation 26 | * Swagger docs 27 | 28 | ## Video structure 29 | 1. Demonstration 30 | 2. Code walk-through 31 | 3. Bootstrap application 32 | * Setup Prisma 33 | * Create Fastify instance 34 | 4. Create user 35 | * Hash password 36 | 5. List users 37 | 6. Login 38 | * fastify-jwt setup 39 | 7. Create product 40 | 8. List products 41 | 42 | # Testing 43 | ## What are we testing with? 44 | * [Node Tap](https://node-tap.org/) - Test framework 45 | * [fastify.inject](https://www.fastify.io/docs/latest/Guides/Testing/#benefits-of-using-fastifyinject) - Inject HTTP requests 46 | * [faker-js](@faker-js/faker) - Generate test data 47 | * [ts-mock-imports](https://www.npmjs.com/package/ts-mock-imports) - Mock imports 48 | 49 | ## What will I learn? 50 | * How to test your API end-to-end 51 | * How to inject http requests to your Fastify application 52 | * How to mock function calls 53 | * How to test with a test database 54 | 55 | ## Where can I learn more about testing Fastify? 56 | * [Unit Test Patterns And Strategies](https://github.com/knockaway/unit-test-patterns-and-strategies) 57 | * [Node Tap documentation](https://node-tap.org/docs/getting-started/) 58 | * [Fastify documentation](https://www.fastify.io/docs/latest/Guides/Testing/) 59 | 60 | -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import Fastify, { FastifyRequest, FastifyReply } from "fastify"; 2 | import fjwt, { JWT } from "fastify-jwt"; 3 | import swagger from "fastify-swagger"; 4 | import { withRefResolver } from "fastify-zod"; 5 | import userRoutes from "./modules/user/user.route"; 6 | import productRoutes from "./modules/product/product.route"; 7 | import { userSchemas } from "./modules/user/user.schema"; 8 | import { productSchemas } from "./modules/product/product.schema"; 9 | import { version } from "../package.json"; 10 | 11 | declare module "fastify" { 12 | interface FastifyRequest { 13 | jwt: JWT; 14 | } 15 | export interface FastifyInstance { 16 | authenticate: any; 17 | } 18 | } 19 | 20 | declare module "fastify-jwt" { 21 | interface FastifyJWT { 22 | user: { 23 | id: number; 24 | email: string; 25 | name: string; 26 | }; 27 | } 28 | } 29 | 30 | function buildServer() { 31 | const server = Fastify(); 32 | 33 | server.register(fjwt, { 34 | secret: "ndkandnan78duy9sau87dbndsa89u7dsy789adb", 35 | }); 36 | 37 | server.decorate( 38 | "authenticate", 39 | async (request: FastifyRequest, reply: FastifyReply) => { 40 | try { 41 | await request.jwtVerify(); 42 | } catch (e) { 43 | return reply.send(e); 44 | } 45 | } 46 | ); 47 | 48 | server.get("/healthcheck", async function () { 49 | return { status: "OK" }; 50 | }); 51 | 52 | server.addHook("preHandler", (req, reply, next) => { 53 | req.jwt = server.jwt; 54 | return next(); 55 | }); 56 | 57 | for (const schema of [...userSchemas, ...productSchemas]) { 58 | server.addSchema(schema); 59 | } 60 | 61 | server.register( 62 | swagger, 63 | withRefResolver({ 64 | routePrefix: "/docs", 65 | exposeRoute: true, 66 | staticCSP: true, 67 | openapi: { 68 | info: { 69 | title: "Fastify API", 70 | description: "API for some products", 71 | version, 72 | }, 73 | }, 74 | }) 75 | ); 76 | 77 | server.register(userRoutes, { prefix: "api/users" }); 78 | server.register(productRoutes, { prefix: "api/products" }); 79 | 80 | return server; 81 | } 82 | 83 | export default buildServer; 84 | -------------------------------------------------------------------------------- /src/modules/user/__test__/login.test.ts: -------------------------------------------------------------------------------- 1 | import faker from "@faker-js/faker"; 2 | import prisma from "../../../utils/prisma"; 3 | import { test } from "tap"; 4 | import buildServer from "../../../server"; 5 | import { UserType } from "fastify-jwt"; 6 | 7 | test("POST `/api/users/login`", async () => { 8 | test("given the email and password are correct", async (t) => { 9 | const name = faker.name.findName(); 10 | const email = faker.internet.email(); 11 | const password = faker.internet.password(); 12 | 13 | const fastify = buildServer(); 14 | 15 | t.teardown(async () => { 16 | fastify.close(); 17 | await prisma.user.deleteMany({}); 18 | }); 19 | 20 | await fastify.inject({ 21 | method: "POST", 22 | url: "/api/users", 23 | payload: { 24 | email, 25 | password, 26 | name, 27 | }, 28 | }); 29 | 30 | const response = await fastify.inject({ 31 | method: "POST", 32 | url: "/api/users/login", 33 | payload: { 34 | email, 35 | password, 36 | }, 37 | }); 38 | 39 | t.equal(response.statusCode, 200); 40 | 41 | const verified = fastify.jwt.verify( 42 | response.json().accessToken 43 | ); 44 | 45 | t.equal(verified.email, email); 46 | t.equal(verified.name, name); 47 | t.type(verified.id, "number"); 48 | t.type(verified.iat, "number"); 49 | }); 50 | 51 | test("given the email and password are not correct", async (t) => { 52 | const name = faker.name.findName(); 53 | const email = faker.internet.email(); 54 | const password = faker.internet.password(); 55 | 56 | const fastify = buildServer(); 57 | 58 | t.teardown(async () => { 59 | fastify.close(); 60 | await prisma.user.deleteMany({}); 61 | }); 62 | 63 | await fastify.inject({ 64 | method: "POST", 65 | url: "/api/users", 66 | payload: { 67 | email, 68 | password, 69 | name, 70 | }, 71 | }); 72 | 73 | const response = await fastify.inject({ 74 | method: "POST", 75 | url: "/api/users/login", 76 | payload: { 77 | email, 78 | password: "wrong", 79 | }, 80 | }); 81 | 82 | t.equal(response.statusCode, 401); 83 | 84 | const json = response.json(); 85 | 86 | t.equal(json.message, "Invalid email or password"); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /src/modules/user/__test__/registerUser.test.ts: -------------------------------------------------------------------------------- 1 | import faker from "@faker-js/faker"; 2 | import { test } from "tap"; 3 | import { ImportMock } from "ts-mock-imports"; 4 | import buildServer from "../../../server"; 5 | import prisma from "../../../utils/prisma"; 6 | import * as userService from "../user.service"; 7 | 8 | test("POST `/api/users` - create user successfully with mock createUser", async (t) => { 9 | const name = faker.name.findName(); 10 | const email = faker.internet.email(); 11 | const password = faker.internet.password(); 12 | const id = Math.floor(Math.random() * 1_000); 13 | 14 | const fastify = buildServer(); 15 | 16 | const stub = ImportMock.mockFunction(userService, "createUser", { 17 | name, 18 | email, 19 | id, 20 | }); 21 | 22 | t.teardown(() => { 23 | fastify.close(); 24 | stub.restore(); 25 | }); 26 | 27 | const response = await fastify.inject({ 28 | method: "POST", 29 | url: "/api/users", 30 | payload: { 31 | email, 32 | password, 33 | name, 34 | }, 35 | }); 36 | 37 | t.equal(response.statusCode, 201); 38 | t.equal(response.headers["content-type"], "application/json; charset=utf-8"); 39 | 40 | const json = response.json(); 41 | 42 | t.equal(json.name, name); 43 | t.equal(json.email, email); 44 | t.equal(json.id, id); 45 | }); 46 | test("POST `/api/users` - create user successfully with test database", async (t) => { 47 | const name = faker.name.findName(); 48 | const email = faker.internet.email(); 49 | const password = faker.internet.password(); 50 | 51 | const fastify = buildServer(); 52 | 53 | t.teardown(async () => { 54 | fastify.close(); 55 | await prisma.user.deleteMany({}); 56 | }); 57 | 58 | const response = await fastify.inject({ 59 | method: "POST", 60 | url: "/api/users", 61 | payload: { 62 | email, 63 | password, 64 | name, 65 | }, 66 | }); 67 | 68 | t.equal(response.statusCode, 201); 69 | t.equal(response.headers["content-type"], "application/json; charset=utf-8"); 70 | 71 | const json = response.json(); 72 | 73 | t.equal(json.name, name); 74 | t.equal(json.email, email); 75 | t.type(json.id, "number"); 76 | }); 77 | test("POST `/api/users` - fail to create a user", async (t) => { 78 | const name = faker.name.findName(); 79 | const password = faker.internet.password(); 80 | 81 | const fastify = buildServer(); 82 | 83 | t.teardown(async () => { 84 | fastify.close(); 85 | await prisma.user.deleteMany({}); 86 | }); 87 | 88 | const response = await fastify.inject({ 89 | method: "POST", 90 | url: "/api/users", 91 | payload: { 92 | password, 93 | name, 94 | }, 95 | }); 96 | 97 | t.equal(response.statusCode, 400); 98 | 99 | const json = response.json(); 100 | 101 | t.equal(json.message, "body should have required property 'email'"); 102 | }); 103 | -------------------------------------------------------------------------------- /.nyc_output/processinfo/index.json: -------------------------------------------------------------------------------- 1 | {"processes":{"2ed0c525-4275-4d6b-9366-c389109cc42b":{"parent":"defb6e19-9ca1-4ca5-a859-ac8b8387cd53","externalId":"src/modules/user/__test__/registerUser.test.ts","children":[]},"46549699-3d4c-40cc-b68f-7a5d8d57f54e":{"parent":"defb6e19-9ca1-4ca5-a859-ac8b8387cd53","externalId":"src/__test__/server.test.ts","children":[]},"c5d44f9d-91ad-40f6-92f4-9e215e65e6d1":{"parent":"defb6e19-9ca1-4ca5-a859-ac8b8387cd53","externalId":"src/modules/user/__test__/login.test.ts","children":[]},"defb6e19-9ca1-4ca5-a859-ac8b8387cd53":{"parent":null,"children":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"]}},"files":{"/Users/tom/projects/fastify-prisma/src/server.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/utils/hash.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/utils/prisma.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"],"/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts":["2ed0c525-4275-4d6b-9366-c389109cc42b","46549699-3d4c-40cc-b68f-7a5d8d57f54e","c5d44f9d-91ad-40f6-92f4-9e215e65e6d1"]},"externalIds":{"src/modules/user/__test__/registerUser.test.ts":{"root":"2ed0c525-4275-4d6b-9366-c389109cc42b","children":[]},"src/__test__/server.test.ts":{"root":"46549699-3d4c-40cc-b68f-7a5d8d57f54e","children":[]},"src/modules/user/__test__/login.test.ts":{"root":"c5d44f9d-91ad-40f6-92f4-9e215e65e6d1","children":[]}}} -------------------------------------------------------------------------------- /Fastify Prisma Tutorial.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "bc1ec926-e77d-4fbe-8e3b-f7c11d897ef1", 4 | "name": "Fastify Prisma Tutorial", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "User", 10 | "item": [ 11 | { 12 | "name": "Create user", 13 | "event": [ 14 | { 15 | "listen": "prerequest", 16 | "script": { 17 | "exec": [ 18 | "let firstName = pm.variables.replaceIn(\"{{$randomFirstName}}\")", 19 | "let lastName = pm.variables.replaceIn(\"{{$randomFirstName}}\")", 20 | "", 21 | "pm.environment.set(\"name\", `${firstName} ${lastName}`)", 22 | "", 23 | "pm.environment.set(\"password\", pm.variables.replaceIn('{{$randomPassword}}'))", 24 | "", 25 | "pm.environment.set(\"email\", `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`)", 26 | "" 27 | ], 28 | "type": "text/javascript" 29 | } 30 | } 31 | ], 32 | "request": { 33 | "method": "POST", 34 | "header": [], 35 | "body": { 36 | "mode": "raw", 37 | "raw": "{\n \"email\": \"{{email}}\",\n \"name\": \"{{name}}\",\n \"password\": \"{{password}}\"\n}", 38 | "options": { 39 | "raw": { 40 | "language": "json" 41 | } 42 | } 43 | }, 44 | "url": { 45 | "raw": "{{host}}/api/users", 46 | "host": [ 47 | "{{host}}" 48 | ], 49 | "path": [ 50 | "api", 51 | "users" 52 | ] 53 | } 54 | }, 55 | "response": [] 56 | }, 57 | { 58 | "name": "Find users", 59 | "request": { 60 | "auth": { 61 | "type": "bearer", 62 | "bearer": [ 63 | { 64 | "key": "token", 65 | "value": "{{accessToken}}", 66 | "type": "string" 67 | } 68 | ] 69 | }, 70 | "method": "GET", 71 | "header": [], 72 | "url": { 73 | "raw": "{{host}}/api/users", 74 | "host": [ 75 | "{{host}}" 76 | ], 77 | "path": [ 78 | "api", 79 | "users" 80 | ] 81 | } 82 | }, 83 | "response": [] 84 | }, 85 | { 86 | "name": "Login", 87 | "event": [ 88 | { 89 | "listen": "test", 90 | "script": { 91 | "exec": [ 92 | "var jsonData = JSON.parse(responseBody);", 93 | "postman.setEnvironmentVariable(\"accessToken\", jsonData.accessToken)" 94 | ], 95 | "type": "text/javascript" 96 | } 97 | } 98 | ], 99 | "request": { 100 | "method": "POST", 101 | "header": [], 102 | "body": { 103 | "mode": "raw", 104 | "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{password}}\"\n}", 105 | "options": { 106 | "raw": { 107 | "language": "json" 108 | } 109 | } 110 | }, 111 | "url": { 112 | "raw": "{{host}}/api/users/login", 113 | "host": [ 114 | "{{host}}" 115 | ], 116 | "path": [ 117 | "api", 118 | "users", 119 | "login" 120 | ] 121 | } 122 | }, 123 | "response": [] 124 | } 125 | ] 126 | }, 127 | { 128 | "name": "Product", 129 | "item": [ 130 | { 131 | "name": "Create product", 132 | "event": [ 133 | { 134 | "listen": "prerequest", 135 | "script": { 136 | "exec": [ 137 | "" 138 | ], 139 | "type": "text/javascript" 140 | } 141 | } 142 | ], 143 | "request": { 144 | "auth": { 145 | "type": "bearer", 146 | "bearer": [ 147 | { 148 | "key": "token", 149 | "value": "{{accessToken}}", 150 | "type": "string" 151 | } 152 | ] 153 | }, 154 | "method": "POST", 155 | "header": [], 156 | "body": { 157 | "mode": "raw", 158 | "raw": "{\n \"title\": \"A cool product\",\n \"price\": 14.99,\n \"content\": \"This is actually an sick product\"\n}", 159 | "options": { 160 | "raw": { 161 | "language": "json" 162 | } 163 | } 164 | }, 165 | "url": { 166 | "raw": "{{host}}/api/products", 167 | "host": [ 168 | "{{host}}" 169 | ], 170 | "path": [ 171 | "api", 172 | "products" 173 | ] 174 | } 175 | }, 176 | "response": [] 177 | }, 178 | { 179 | "name": "Get products", 180 | "request": { 181 | "method": "GET", 182 | "header": [], 183 | "url": { 184 | "raw": "{{host}}/api/products", 185 | "host": [ 186 | "{{host}}" 187 | ], 188 | "path": [ 189 | "api", 190 | "products" 191 | ] 192 | } 193 | }, 194 | "response": [] 195 | } 196 | ] 197 | } 198 | ] 199 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | 26 | /* Modules */ 27 | "module": "commonjs" /* Specify what module code is generated. */, 28 | // "rootDir": "./", /* Specify the root folder within your source files. */ 29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | "resolveJsonModule": true /* Enable importing .json files */, 37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 38 | 39 | /* JavaScript Support */ 40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 43 | 44 | /* Emit */ 45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 50 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 51 | // "removeComments": true, /* Disable emitting comments. */ 52 | // "noEmit": true, /* Disable emitting files from a compilation. */ 53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 61 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 68 | 69 | /* Interop Constraints */ 70 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 71 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 72 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, 73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 74 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 75 | 76 | /* Type Checking */ 77 | "strict": true /* Enable all strict type-checking options. */, 78 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 79 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 96 | 97 | /* Completeness */ 98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /.nyc_output/2ed0c525-4275-4d6b-9366-c389109cc42b.json: -------------------------------------------------------------------------------- 1 | {"/Users/tom/projects/fastify-prisma/src/server.ts":{"path":"/Users/tom/projects/fastify-prisma/src/server.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":22},"end":{"line":13,"column":1}},"13":{"start":{"line":12,"column":4},"end":{"line":12,"column":62}},"14":{"start":{"line":14,"column":0},"end":{"line":14,"column":62}},"15":{"start":{"line":15,"column":18},"end":{"line":15,"column":53}},"16":{"start":{"line":16,"column":22},"end":{"line":16,"column":61}},"17":{"start":{"line":17,"column":26},"end":{"line":17,"column":69}},"18":{"start":{"line":18,"column":22},"end":{"line":18,"column":44}},"19":{"start":{"line":19,"column":21},"end":{"line":19,"column":74}},"20":{"start":{"line":20,"column":24},"end":{"line":20,"column":83}},"21":{"start":{"line":21,"column":22},"end":{"line":21,"column":59}},"22":{"start":{"line":22,"column":25},"end":{"line":22,"column":68}},"23":{"start":{"line":23,"column":23},"end":{"line":23,"column":49}},"24":{"start":{"line":25,"column":19},"end":{"line":25,"column":43}},"25":{"start":{"line":26,"column":4},"end":{"line":28,"column":7}},"26":{"start":{"line":29,"column":4},"end":{"line":36,"column":8}},"27":{"start":{"line":29,"column":56},"end":{"line":36,"column":6}},"28":{"start":{"line":30,"column":8},"end":{"line":35,"column":9}},"29":{"start":{"line":31,"column":12},"end":{"line":31,"column":38}},"30":{"start":{"line":34,"column":12},"end":{"line":34,"column":33}},"31":{"start":{"line":37,"column":4},"end":{"line":41,"column":7}},"32":{"start":{"line":38,"column":8},"end":{"line":40,"column":11}},"33":{"start":{"line":39,"column":12},"end":{"line":39,"column":36}},"34":{"start":{"line":42,"column":4},"end":{"line":45,"column":7}},"35":{"start":{"line":43,"column":8},"end":{"line":43,"column":29}},"36":{"start":{"line":44,"column":8},"end":{"line":44,"column":22}},"37":{"start":{"line":46,"column":4},"end":{"line":48,"column":5}},"38":{"start":{"line":47,"column":8},"end":{"line":47,"column":33}},"39":{"start":{"line":49,"column":4},"end":{"line":60,"column":8}},"40":{"start":{"line":61,"column":4},"end":{"line":61,"column":67}},"41":{"start":{"line":62,"column":4},"end":{"line":62,"column":73}},"42":{"start":{"line":63,"column":4},"end":{"line":63,"column":18}},"43":{"start":{"line":65,"column":0},"end":{"line":65,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":56},"end":{"line":11,"column":57}},"loc":{"start":{"line":11,"column":71},"end":{"line":13,"column":1}},"line":11},"8":{"name":"buildServer","decl":{"start":{"line":24,"column":9},"end":{"line":24,"column":20}},"loc":{"start":{"line":24,"column":23},"end":{"line":64,"column":1}},"line":24},"9":{"name":"(anonymous_9)","decl":{"start":{"line":29,"column":36},"end":{"line":29,"column":37}},"loc":{"start":{"line":29,"column":56},"end":{"line":36,"column":6}},"line":29},"10":{"name":"(anonymous_10)","decl":{"start":{"line":29,"column":88},"end":{"line":29,"column":89}},"loc":{"start":{"line":29,"column":101},"end":{"line":36,"column":5}},"line":29},"11":{"name":"(anonymous_11)","decl":{"start":{"line":37,"column":31},"end":{"line":37,"column":32}},"loc":{"start":{"line":37,"column":43},"end":{"line":41,"column":5}},"line":37},"12":{"name":"(anonymous_12)","decl":{"start":{"line":38,"column":47},"end":{"line":38,"column":48}},"loc":{"start":{"line":38,"column":60},"end":{"line":40,"column":9}},"line":38},"13":{"name":"(anonymous_13)","decl":{"start":{"line":42,"column":33},"end":{"line":42,"column":34}},"loc":{"start":{"line":42,"column":55},"end":{"line":45,"column":5}},"line":42}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8},"5":{"loc":{"start":{"line":11,"column":22},"end":{"line":13,"column":1}},"type":"binary-expr","locations":[{"start":{"line":11,"column":23},"end":{"line":11,"column":27}},{"start":{"line":11,"column":31},"end":{"line":11,"column":51}},{"start":{"line":11,"column":56},"end":{"line":13,"column":1}}],"line":11},"6":{"loc":{"start":{"line":12,"column":11},"end":{"line":12,"column":61}},"type":"cond-expr","locations":[{"start":{"line":12,"column":37},"end":{"line":12,"column":40}},{"start":{"line":12,"column":43},"end":{"line":12,"column":61}}],"line":12},"7":{"loc":{"start":{"line":12,"column":12},"end":{"line":12,"column":33}},"type":"binary-expr","locations":[{"start":{"line":12,"column":12},"end":{"line":12,"column":15}},{"start":{"line":12,"column":19},"end":{"line":12,"column":33}}],"line":12}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":1,"13":5,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":1,"24":3,"25":3,"26":3,"27":0,"28":0,"29":0,"30":0,"31":3,"32":0,"33":0,"34":3,"35":2,"36":2,"37":3,"38":21,"39":3,"40":3,"41":3,"42":3,"43":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":5,"8":3,"9":0,"10":0,"11":0,"12":0,"13":2},"b":{"0":[1,1,1],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[1,1,1],"6":[2,3],"7":[5,5]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/server.ts","sources":["/Users/tom/projects/fastify-prisma/src/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,sDAAgE;AAChE,8DAAwC;AACxC,sEAAsC;AACtC,6CAA8C;AAC9C,2EAAmD;AACnD,oFAA4D;AAC5D,4DAAyD;AACzD,qEAAkE;AAClE,kDAA0C;AAqB1C,SAAS,WAAW;IAClB,MAAM,MAAM,GAAG,IAAA,iBAAO,GAAE,CAAC;IAEzB,MAAM,CAAC,QAAQ,CAAC,qBAAI,EAAE;QACpB,MAAM,EAAE,yCAAyC;KAClD,CAAC,CAAC;IAEH,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,CAAO,OAAuB,EAAE,KAAmB,EAAE,EAAE;QACrD,IAAI;YACF,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;SAC3B;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACtB;IACH,CAAC,CAAA,CACF,CAAC;IAEF,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE;;YACzB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1B,CAAC;KAAA,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAChD,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACrB,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,yBAAW,EAAE,GAAG,+BAAc,CAAC,EAAE;QACxD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;KAC1B;IAED,MAAM,CAAC,QAAQ,CACb,yBAAO,EACP,IAAA,6BAAe,EAAC;QACd,WAAW,EAAE,OAAO;QACpB,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,IAAI;QACf,OAAO,EAAE;YACP,IAAI,EAAE;gBACJ,KAAK,EAAE,aAAa;gBACpB,WAAW,EAAE,uBAAuB;gBACpC,OAAO,EAAP,sBAAO;aACR;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,QAAQ,CAAC,oBAAU,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACrD,MAAM,CAAC,QAAQ,CAAC,uBAAa,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;IAE3D,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kBAAe,WAAW,CAAC","sourcesContent":["import Fastify, { FastifyRequest, FastifyReply } from \"fastify\";\nimport fjwt, { JWT } from \"fastify-jwt\";\nimport swagger from \"fastify-swagger\";\nimport { withRefResolver } from \"fastify-zod\";\nimport userRoutes from \"./modules/user/user.route\";\nimport productRoutes from \"./modules/product/product.route\";\nimport { userSchemas } from \"./modules/user/user.schema\";\nimport { productSchemas } from \"./modules/product/product.schema\";\nimport { version } from \"../package.json\";\n\ndeclare module \"fastify\" {\n interface FastifyRequest {\n jwt: JWT;\n }\n export interface FastifyInstance {\n authenticate: any;\n }\n}\n\ndeclare module \"fastify-jwt\" {\n interface FastifyJWT {\n user: {\n id: number;\n email: string;\n name: string;\n };\n }\n}\n\nfunction buildServer() {\n const server = Fastify();\n\n server.register(fjwt, {\n secret: \"ndkandnan78duy9sau87dbndsa89u7dsy789adb\",\n });\n\n server.decorate(\n \"authenticate\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n try {\n await request.jwtVerify();\n } catch (e) {\n return reply.send(e);\n }\n }\n );\n\n server.get(\"/healthcheck\", async function () {\n return { status: \"OK\" };\n });\n\n server.addHook(\"preHandler\", (req, reply, next) => {\n req.jwt = server.jwt;\n return next();\n });\n\n for (const schema of [...userSchemas, ...productSchemas]) {\n server.addSchema(schema);\n }\n\n server.register(\n swagger,\n withRefResolver({\n routePrefix: \"/docs\",\n exposeRoute: true,\n staticCSP: true,\n openapi: {\n info: {\n title: \"Fastify API\",\n description: \"API for some products\",\n version,\n },\n },\n })\n );\n\n server.register(userRoutes, { prefix: \"api/users\" });\n server.register(productRoutes, { prefix: \"api/products\" });\n\n return server;\n}\n\nexport default buildServer;\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d110024f020ad2420cc48799519f114571270536","contentHash":"af2f7fa46fa7406659b83a18607f97c346aa47e00d1940e8fbe948e06fb58dac"},"/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":0},"end":{"line":11,"column":62}},"13":{"start":{"line":12,"column":26},"end":{"line":12,"column":54}},"14":{"start":{"line":13,"column":22},"end":{"line":13,"column":46}},"15":{"start":{"line":15,"column":4},"end":{"line":35,"column":7}},"16":{"start":{"line":16,"column":8},"end":{"line":23,"column":50}},"17":{"start":{"line":24,"column":8},"end":{"line":31,"column":43}},"18":{"start":{"line":32,"column":8},"end":{"line":34,"column":46}},"19":{"start":{"line":37,"column":0},"end":{"line":37,"column":29}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"userRoutes","decl":{"start":{"line":14,"column":9},"end":{"line":14,"column":19}},"loc":{"start":{"line":14,"column":28},"end":{"line":36,"column":1}},"line":14},"8":{"name":"(anonymous_8)","decl":{"start":{"line":15,"column":43},"end":{"line":15,"column":44}},"loc":{"start":{"line":15,"column":56},"end":{"line":35,"column":5}},"line":15}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8}},"s":{"0":1,"1":0,"2":0,"3":3,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":3,"11":3,"12":1,"13":1,"14":1,"15":3,"16":3,"17":3,"18":3,"19":1},"f":{"0":3,"1":0,"2":0,"3":3,"4":0,"5":0,"6":3,"7":3,"8":3},"b":{"0":[1,1,1],"1":[0,0],"2":[3,3],"3":[3,0],"4":[3,3]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts"],"names":[],"mappings":";;;;;;;;;;;AACA,uDAI2B;AAC3B,+CAAqC;AAErC,SAAe,UAAU,CAAC,MAAuB;;QAC/C,MAAM,CAAC,IAAI,CACT,GAAG,EACH;YACE,MAAM,EAAE;gBACN,IAAI,EAAE,IAAA,kBAAI,EAAC,kBAAkB,CAAC;gBAC9B,QAAQ,EAAE;oBACR,GAAG,EAAE,IAAA,kBAAI,EAAC,0BAA0B,CAAC;iBACtC;aACF;SACF,EACD,qCAAmB,CACpB,CAAC;QAEF,MAAM,CAAC,IAAI,CACT,QAAQ,EACR;YACE,MAAM,EAAE;gBACN,IAAI,EAAE,IAAA,kBAAI,EAAC,aAAa,CAAC;gBACzB,QAAQ,EAAE;oBACR,GAAG,EAAE,IAAA,kBAAI,EAAC,qBAAqB,CAAC;iBACjC;aACF;SACF,EACD,8BAAY,CACb,CAAC;QAEF,MAAM,CAAC,GAAG,CACR,GAAG,EACH;YACE,UAAU,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC;SAClC,EACD,iCAAe,CAChB,CAAC;IACJ,CAAC;CAAA;AAED,kBAAe,UAAU,CAAC","sourcesContent":["import { FastifyInstance } from \"fastify\";\nimport {\n loginHandler,\n registerUserHandler,\n getUsersHandler,\n} from \"./user.controller\";\nimport { $ref } from \"./user.schema\";\n\nasync function userRoutes(server: FastifyInstance) {\n server.post(\n \"/\",\n {\n schema: {\n body: $ref(\"createUserSchema\"),\n response: {\n 201: $ref(\"createUserResponseSchema\"),\n },\n },\n },\n registerUserHandler\n );\n\n server.post(\n \"/login\",\n {\n schema: {\n body: $ref(\"loginSchema\"),\n response: {\n 200: $ref(\"loginResponseSchema\"),\n },\n },\n },\n loginHandler\n );\n\n server.get(\n \"/\",\n {\n preHandler: [server.authenticate],\n },\n getUsersHandler\n );\n}\n\nexport default userRoutes;\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"fcf266702283962cfc6c149b84a59ef5bc8e9cf1","contentHash":"7d4d49ab72c99eb67162f99489d30c0ee18a78071dffa23f3cdf52299a9d45ae"},"/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":13},"end":{"line":21,"column":1}},"13":{"start":{"line":12,"column":12},"end":{"line":12,"column":14}},"14":{"start":{"line":13,"column":4},"end":{"line":14,"column":20}},"15":{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},"16":{"start":{"line":14,"column":8},"end":{"line":14,"column":20}},"17":{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},"18":{"start":{"line":16,"column":8},"end":{"line":19,"column":9}},"19":{"start":{"line":16,"column":21},"end":{"line":16,"column":22}},"20":{"start":{"line":16,"column":28},"end":{"line":16,"column":59}},"21":{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},"22":{"start":{"line":18,"column":16},"end":{"line":18,"column":34}},"23":{"start":{"line":20,"column":4},"end":{"line":20,"column":13}},"24":{"start":{"line":22,"column":0},"end":{"line":22,"column":62}},"25":{"start":{"line":23,"column":0},"end":{"line":23,"column":86}},"26":{"start":{"line":24,"column":15},"end":{"line":24,"column":42}},"27":{"start":{"line":25,"column":23},"end":{"line":25,"column":48}},"28":{"start":{"line":27,"column":4},"end":{"line":37,"column":7}},"29":{"start":{"line":28,"column":21},"end":{"line":28,"column":33}},"30":{"start":{"line":29,"column":8},"end":{"line":36,"column":9}},"31":{"start":{"line":30,"column":25},"end":{"line":30,"column":67}},"32":{"start":{"line":31,"column":12},"end":{"line":31,"column":46}},"33":{"start":{"line":34,"column":12},"end":{"line":34,"column":27}},"34":{"start":{"line":35,"column":12},"end":{"line":35,"column":43}},"35":{"start":{"line":39,"column":0},"end":{"line":39,"column":50}},"36":{"start":{"line":41,"column":4},"end":{"line":64,"column":7}},"37":{"start":{"line":42,"column":21},"end":{"line":42,"column":33}},"38":{"start":{"line":44,"column":21},"end":{"line":44,"column":74}},"39":{"start":{"line":45,"column":8},"end":{"line":49,"column":9}},"40":{"start":{"line":46,"column":12},"end":{"line":48,"column":15}},"41":{"start":{"line":51,"column":32},"end":{"line":55,"column":10}},"42":{"start":{"line":56,"column":8},"end":{"line":60,"column":9}},"43":{"start":{"line":57,"column":39},"end":{"line":57,"column":43}},"44":{"start":{"line":57,"column":52},"end":{"line":57,"column":86}},"45":{"start":{"line":59,"column":12},"end":{"line":59,"column":59}},"46":{"start":{"line":61,"column":8},"end":{"line":63,"column":11}},"47":{"start":{"line":66,"column":0},"end":{"line":66,"column":36}},"48":{"start":{"line":68,"column":4},"end":{"line":71,"column":7}},"49":{"start":{"line":69,"column":22},"end":{"line":69,"column":59}},"50":{"start":{"line":70,"column":8},"end":{"line":70,"column":21}},"51":{"start":{"line":73,"column":0},"end":{"line":73,"column":42}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":38},"end":{"line":11,"column":39}},"loc":{"start":{"line":11,"column":54},"end":{"line":21,"column":1}},"line":11},"8":{"name":"registerUserHandler","decl":{"start":{"line":26,"column":9},"end":{"line":26,"column":28}},"loc":{"start":{"line":26,"column":45},"end":{"line":38,"column":1}},"line":26},"9":{"name":"(anonymous_9)","decl":{"start":{"line":27,"column":43},"end":{"line":27,"column":44}},"loc":{"start":{"line":27,"column":56},"end":{"line":37,"column":5}},"line":27},"10":{"name":"loginHandler","decl":{"start":{"line":40,"column":9},"end":{"line":40,"column":21}},"loc":{"start":{"line":40,"column":38},"end":{"line":65,"column":1}},"line":40},"11":{"name":"(anonymous_11)","decl":{"start":{"line":41,"column":43},"end":{"line":41,"column":44}},"loc":{"start":{"line":41,"column":56},"end":{"line":64,"column":5}},"line":41},"12":{"name":"getUsersHandler","decl":{"start":{"line":67,"column":9},"end":{"line":67,"column":24}},"loc":{"start":{"line":67,"column":27},"end":{"line":72,"column":1}},"line":67},"13":{"name":"(anonymous_13)","decl":{"start":{"line":68,"column":43},"end":{"line":68,"column":44}},"loc":{"start":{"line":68,"column":56},"end":{"line":71,"column":5}},"line":68}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8},"5":{"loc":{"start":{"line":11,"column":13},"end":{"line":21,"column":1}},"type":"binary-expr","locations":[{"start":{"line":11,"column":14},"end":{"line":11,"column":18}},{"start":{"line":11,"column":22},"end":{"line":11,"column":33}},{"start":{"line":11,"column":38},"end":{"line":21,"column":1}}],"line":11},"6":{"loc":{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},"type":"if","locations":[{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},{"start":{"line":13,"column":21},"end":{"line":14,"column":20}}],"line":13},"7":{"loc":{"start":{"line":13,"column":25},"end":{"line":13,"column":87}},"type":"binary-expr","locations":[{"start":{"line":13,"column":25},"end":{"line":13,"column":67}},{"start":{"line":13,"column":71},"end":{"line":13,"column":87}}],"line":13},"8":{"loc":{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},{"start":{"line":15,"column":4},"end":{"line":19,"column":9}}],"line":15},"9":{"loc":{"start":{"line":15,"column":8},"end":{"line":15,"column":71}},"type":"binary-expr","locations":[{"start":{"line":15,"column":8},"end":{"line":15,"column":17}},{"start":{"line":15,"column":21},"end":{"line":15,"column":71}}],"line":15},"10":{"loc":{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},"type":"if","locations":[{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},{"start":{"line":17,"column":12},"end":{"line":18,"column":34}}],"line":17},"11":{"loc":{"start":{"line":17,"column":16},"end":{"line":17,"column":90}},"type":"binary-expr","locations":[{"start":{"line":17,"column":16},"end":{"line":17,"column":35}},{"start":{"line":17,"column":39},"end":{"line":17,"column":90}}],"line":17},"12":{"loc":{"start":{"line":45,"column":8},"end":{"line":49,"column":9}},"type":"if","locations":[{"start":{"line":45,"column":8},"end":{"line":49,"column":9}},{"start":{"line":45,"column":8},"end":{"line":49,"column":9}}],"line":45},"13":{"loc":{"start":{"line":56,"column":8},"end":{"line":60,"column":9}},"type":"if","locations":[{"start":{"line":56,"column":8},"end":{"line":60,"column":9}},{"start":{"line":56,"column":8},"end":{"line":60,"column":9}}],"line":56}},"s":{"0":1,"1":2,"2":1,"3":2,"4":2,"5":2,"6":0,"7":0,"8":0,"9":0,"10":4,"11":2,"12":1,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":1,"25":1,"26":1,"27":1,"28":2,"29":2,"30":2,"31":2,"32":2,"33":0,"34":0,"35":1,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":1,"48":0,"49":0,"50":0,"51":1},"f":{"0":2,"1":2,"2":1,"3":2,"4":2,"5":0,"6":4,"7":0,"8":2,"9":2,"10":0,"11":0,"12":0,"13":0},"b":{"0":[1,1,1],"1":[1,1],"2":[2,2],"3":[2,2],"4":[2,2],"5":[1,1,1],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AACA,2CAAkD;AAElD,iDAAwE;AAExE,SAAsB,mBAAmB,CACvC,OAEE,EACF,KAAmB;;QAEnB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAE1B,IAAI;YACF,MAAM,IAAI,GAAG,MAAM,IAAA,yBAAU,EAAC,IAAI,CAAC,CAAC;YAEpC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SACnC;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACf,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAChC;IACH,CAAC;CAAA;AAhBD,kDAgBC;AAED,SAAsB,YAAY,CAChC,OAEE,EACF,KAAmB;;QAEnB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAE1B,uBAAuB;QACvB,MAAM,IAAI,GAAG,MAAM,IAAA,8BAAe,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE/C,IAAI,CAAC,IAAI,EAAE;YACT,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC1B,OAAO,EAAE,2BAA2B;aACrC,CAAC,CAAC;SACJ;QAED,kBAAkB;QAClB,MAAM,eAAe,GAAG,IAAA,qBAAc,EAAC;YACrC,iBAAiB,EAAE,IAAI,CAAC,QAAQ;YAChC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,QAAQ;SACpB,CAAC,CAAC;QAEH,IAAI,eAAe,EAAE;YACnB,MAAM,EAAE,QAAQ,EAAE,IAAI,KAAc,IAAI,EAAb,IAAI,UAAK,IAAI,EAAlC,oBAA2B,CAAO,CAAC;YACzC,wBAAwB;YACxB,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SAChD;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,OAAO,EAAE,2BAA2B;SACrC,CAAC,CAAC;IACL,CAAC;CAAA;AAjCD,oCAiCC;AAED,SAAsB,eAAe;;QACnC,MAAM,KAAK,GAAG,MAAM,IAAA,wBAAS,GAAE,CAAC;QAEhC,OAAO,KAAK,CAAC;IACf,CAAC;CAAA;AAJD,0CAIC","sourcesContent":["import { FastifyReply, FastifyRequest } from \"fastify\";\nimport { verifyPassword } from \"../../utils/hash\";\nimport { CreateUserInput, LoginInput } from \"./user.schema\";\nimport { createUser, findUserByEmail, findUsers } from \"./user.service\";\n\nexport async function registerUserHandler(\n request: FastifyRequest<{\n Body: CreateUserInput;\n }>,\n reply: FastifyReply\n) {\n const body = request.body;\n\n try {\n const user = await createUser(body);\n\n return reply.code(201).send(user);\n } catch (e) {\n console.log(e);\n return reply.code(500).send(e);\n }\n}\n\nexport async function loginHandler(\n request: FastifyRequest<{\n Body: LoginInput;\n }>,\n reply: FastifyReply\n) {\n const body = request.body;\n\n // find a user by email\n const user = await findUserByEmail(body.email);\n\n if (!user) {\n return reply.code(401).send({\n message: \"Invalid email or password\",\n });\n }\n\n // verify password\n const correctPassword = verifyPassword({\n candidatePassword: body.password,\n salt: user.salt,\n hash: user.password,\n });\n\n if (correctPassword) {\n const { password, salt, ...rest } = user;\n // generate access token\n return { accessToken: request.jwt.sign(rest) };\n }\n\n return reply.code(401).send({\n message: \"Invalid email or password\",\n });\n}\n\nexport async function getUsersHandler() {\n const users = await findUsers();\n\n return users;\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"66390af8925f32e5101fd5f4c4d5b5db4544e3d1","contentHash":"a4d44072d26a5fb12cbb748def8fd41b639d96c5508a622593dde931d849d1fa"},"/Users/tom/projects/fastify-prisma/src/utils/hash.ts":{"path":"/Users/tom/projects/fastify-prisma/src/utils/hash.ts","statementMap":{"0":{"start":{"line":2,"column":22},"end":{"line":4,"column":1}},"1":{"start":{"line":3,"column":4},"end":{"line":3,"column":62}},"2":{"start":{"line":5,"column":0},"end":{"line":5,"column":62}},"3":{"start":{"line":6,"column":0},"end":{"line":6,"column":55}},"4":{"start":{"line":7,"column":17},"end":{"line":7,"column":51}},"5":{"start":{"line":14,"column":17},"end":{"line":14,"column":65}},"6":{"start":{"line":18,"column":17},"end":{"line":20,"column":24}},"7":{"start":{"line":21,"column":4},"end":{"line":21,"column":26}},"8":{"start":{"line":23,"column":0},"end":{"line":23,"column":36}},"9":{"start":{"line":29,"column":26},"end":{"line":31,"column":24}},"10":{"start":{"line":36,"column":4},"end":{"line":36,"column":34}},"11":{"start":{"line":38,"column":0},"end":{"line":38,"column":40}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":56},"end":{"line":2,"column":57}},"loc":{"start":{"line":2,"column":71},"end":{"line":4,"column":1}},"line":2},"1":{"name":"hashPassword","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":21}},"loc":{"start":{"line":8,"column":32},"end":{"line":22,"column":1}},"line":8},"2":{"name":"verifyPassword","decl":{"start":{"line":24,"column":9},"end":{"line":24,"column":23}},"loc":{"start":{"line":24,"column":60},"end":{"line":37,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":22},"end":{"line":4,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":23},"end":{"line":2,"column":27}},{"start":{"line":2,"column":31},"end":{"line":2,"column":51}},{"start":{"line":2,"column":56},"end":{"line":4,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":11},"end":{"line":3,"column":61}},"type":"cond-expr","locations":[{"start":{"line":3,"column":37},"end":{"line":3,"column":40}},{"start":{"line":3,"column":43},"end":{"line":3,"column":61}}],"line":3},"2":{"loc":{"start":{"line":3,"column":12},"end":{"line":3,"column":33}},"type":"binary-expr","locations":[{"start":{"line":3,"column":12},"end":{"line":3,"column":15}},{"start":{"line":3,"column":19},"end":{"line":3,"column":33}}],"line":3}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":0,"10":0,"11":1},"f":{"0":1,"1":1,"2":0},"b":{"0":[1,1,1],"1":[0,1],"2":[1,1]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/utils/hash.ts","sources":["/Users/tom/projects/fastify-prisma/src/utils/hash.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAE5B,SAAgB,YAAY,CAAC,QAAgB;IAC3C;;;;OAIG;IACH,MAAM,IAAI,GAAG,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD;;OAEG;IACH,MAAM,IAAI,GAAG,gBAAM;SAChB,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,CAAC;SAC9C,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEnB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC;AAhBD,oCAgBC;AAED,SAAgB,cAAc,CAAC,EAC7B,iBAAiB,EACjB,IAAI,EACJ,IAAI,GAKL;IACC;;;OAGG;IACH,MAAM,aAAa,GAAG,gBAAM;SACzB,UAAU,CAAC,iBAAiB,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,CAAC;SACvD,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEnB;;;OAGG;IAEH,OAAO,aAAa,KAAK,IAAI,CAAC;AAChC,CAAC;AAvBD,wCAuBC","sourcesContent":["import crypto from \"crypto\";\n\nexport function hashPassword(password: string) {\n /*\n * Creating a unique salt for a particular user\n * Salt is a random bit of data added to the user's password\n * Salt means that every password's hash is going to be unique\n */\n const salt = crypto.randomBytes(16).toString(\"hex\");\n\n /*\n * Create a hash with 1000 iterations\n */\n const hash = crypto\n .pbkdf2Sync(password, salt, 1000, 64, \"sha512\")\n .toString(\"hex\");\n\n return { hash, salt };\n}\n\nexport function verifyPassword({\n candidatePassword,\n salt,\n hash,\n}: {\n candidatePassword: string;\n salt: string;\n hash: string;\n}) {\n /*\n * Create a hash with the salt from the user and the password\n * the user tried to login with\n */\n const candidateHash = crypto\n .pbkdf2Sync(candidatePassword, salt, 1000, 64, \"sha512\")\n .toString(\"hex\");\n\n /*\n * If the hash matches the hash we have stored for the user\n * then the candidate password is correct\n */\n\n return candidateHash === hash;\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"ea59f0a61b9dd5cc16f317308b72be3f944f36c6","contentHash":"c75bb33ff482332961e8a68862efd412f509cab5dea4eb2e136c472ed5fc7623"},"/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":13},"end":{"line":21,"column":1}},"13":{"start":{"line":12,"column":12},"end":{"line":12,"column":14}},"14":{"start":{"line":13,"column":4},"end":{"line":14,"column":20}},"15":{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},"16":{"start":{"line":14,"column":8},"end":{"line":14,"column":20}},"17":{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},"18":{"start":{"line":16,"column":8},"end":{"line":19,"column":9}},"19":{"start":{"line":16,"column":21},"end":{"line":16,"column":22}},"20":{"start":{"line":16,"column":28},"end":{"line":16,"column":59}},"21":{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},"22":{"start":{"line":18,"column":16},"end":{"line":18,"column":34}},"23":{"start":{"line":20,"column":4},"end":{"line":20,"column":13}},"24":{"start":{"line":22,"column":22},"end":{"line":24,"column":1}},"25":{"start":{"line":23,"column":4},"end":{"line":23,"column":62}},"26":{"start":{"line":25,"column":0},"end":{"line":25,"column":62}},"27":{"start":{"line":26,"column":0},"end":{"line":26,"column":74}},"28":{"start":{"line":27,"column":15},"end":{"line":27,"column":42}},"29":{"start":{"line":28,"column":17},"end":{"line":28,"column":63}},"30":{"start":{"line":30,"column":4},"end":{"line":37,"column":7}},"31":{"start":{"line":31,"column":29},"end":{"line":31,"column":34}},"32":{"start":{"line":31,"column":43},"end":{"line":31,"column":70}},"33":{"start":{"line":32,"column":31},"end":{"line":32,"column":65}},"34":{"start":{"line":33,"column":21},"end":{"line":35,"column":10}},"35":{"start":{"line":36,"column":8},"end":{"line":36,"column":20}},"36":{"start":{"line":39,"column":0},"end":{"line":39,"column":32}},"37":{"start":{"line":41,"column":4},"end":{"line":47,"column":7}},"38":{"start":{"line":42,"column":8},"end":{"line":46,"column":11}},"39":{"start":{"line":49,"column":0},"end":{"line":49,"column":42}},"40":{"start":{"line":51,"column":4},"end":{"line":59,"column":7}},"41":{"start":{"line":52,"column":8},"end":{"line":58,"column":11}},"42":{"start":{"line":61,"column":0},"end":{"line":61,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":38},"end":{"line":11,"column":39}},"loc":{"start":{"line":11,"column":54},"end":{"line":21,"column":1}},"line":11},"8":{"name":"(anonymous_8)","decl":{"start":{"line":22,"column":56},"end":{"line":22,"column":57}},"loc":{"start":{"line":22,"column":71},"end":{"line":24,"column":1}},"line":22},"9":{"name":"createUser","decl":{"start":{"line":29,"column":9},"end":{"line":29,"column":19}},"loc":{"start":{"line":29,"column":27},"end":{"line":38,"column":1}},"line":29},"10":{"name":"(anonymous_10)","decl":{"start":{"line":30,"column":43},"end":{"line":30,"column":44}},"loc":{"start":{"line":30,"column":56},"end":{"line":37,"column":5}},"line":30},"11":{"name":"findUserByEmail","decl":{"start":{"line":40,"column":9},"end":{"line":40,"column":24}},"loc":{"start":{"line":40,"column":32},"end":{"line":48,"column":1}},"line":40},"12":{"name":"(anonymous_12)","decl":{"start":{"line":41,"column":43},"end":{"line":41,"column":44}},"loc":{"start":{"line":41,"column":56},"end":{"line":47,"column":5}},"line":41},"13":{"name":"findUsers","decl":{"start":{"line":50,"column":9},"end":{"line":50,"column":18}},"loc":{"start":{"line":50,"column":21},"end":{"line":60,"column":1}},"line":50},"14":{"name":"(anonymous_14)","decl":{"start":{"line":51,"column":43},"end":{"line":51,"column":44}},"loc":{"start":{"line":51,"column":56},"end":{"line":59,"column":5}},"line":51}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8},"5":{"loc":{"start":{"line":11,"column":13},"end":{"line":21,"column":1}},"type":"binary-expr","locations":[{"start":{"line":11,"column":14},"end":{"line":11,"column":18}},{"start":{"line":11,"column":22},"end":{"line":11,"column":33}},{"start":{"line":11,"column":38},"end":{"line":21,"column":1}}],"line":11},"6":{"loc":{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},"type":"if","locations":[{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},{"start":{"line":13,"column":21},"end":{"line":14,"column":20}}],"line":13},"7":{"loc":{"start":{"line":13,"column":25},"end":{"line":13,"column":87}},"type":"binary-expr","locations":[{"start":{"line":13,"column":25},"end":{"line":13,"column":67}},{"start":{"line":13,"column":71},"end":{"line":13,"column":87}}],"line":13},"8":{"loc":{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},{"start":{"line":15,"column":4},"end":{"line":19,"column":9}}],"line":15},"9":{"loc":{"start":{"line":15,"column":8},"end":{"line":15,"column":71}},"type":"binary-expr","locations":[{"start":{"line":15,"column":8},"end":{"line":15,"column":17}},{"start":{"line":15,"column":21},"end":{"line":15,"column":71}}],"line":15},"10":{"loc":{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},"type":"if","locations":[{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},{"start":{"line":17,"column":12},"end":{"line":18,"column":34}}],"line":17},"11":{"loc":{"start":{"line":17,"column":16},"end":{"line":17,"column":90}},"type":"binary-expr","locations":[{"start":{"line":17,"column":16},"end":{"line":17,"column":35}},{"start":{"line":17,"column":39},"end":{"line":17,"column":90}}],"line":17},"12":{"loc":{"start":{"line":22,"column":22},"end":{"line":24,"column":1}},"type":"binary-expr","locations":[{"start":{"line":22,"column":23},"end":{"line":22,"column":27}},{"start":{"line":22,"column":31},"end":{"line":22,"column":51}},{"start":{"line":22,"column":56},"end":{"line":24,"column":1}}],"line":22},"13":{"loc":{"start":{"line":23,"column":11},"end":{"line":23,"column":61}},"type":"cond-expr","locations":[{"start":{"line":23,"column":37},"end":{"line":23,"column":40}},{"start":{"line":23,"column":43},"end":{"line":23,"column":61}}],"line":23},"14":{"loc":{"start":{"line":23,"column":12},"end":{"line":23,"column":33}},"type":"binary-expr","locations":[{"start":{"line":23,"column":12},"end":{"line":23,"column":15}},{"start":{"line":23,"column":19},"end":{"line":23,"column":33}}],"line":23}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":0,"7":0,"8":0,"9":0,"10":2,"11":1,"12":1,"13":1,"14":1,"15":3,"16":2,"17":1,"18":1,"19":1,"20":1,"21":0,"22":0,"23":1,"24":1,"25":1,"26":1,"27":1,"28":1,"29":1,"30":1,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":0,"38":0,"39":1,"40":0,"41":0,"42":1},"f":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":2,"7":1,"8":1,"9":1,"10":1,"11":0,"12":0,"13":0,"14":0},"b":{"0":[1,1,1],"1":[0,1],"2":[1,1],"3":[1,1],"4":[1,1],"5":[1,1,1],"6":[2,1],"7":[3,3],"8":[1,0],"9":[1,1],"10":[0,0],"11":[0,0],"12":[1,1,1],"13":[1,0],"14":[1,1]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAgD;AAChD,gEAAwC;AAGxC,SAAsB,UAAU,CAAC,KAAsB;;QACrD,MAAM,EAAE,QAAQ,KAAc,KAAK,EAAd,IAAI,UAAK,KAAK,EAA7B,YAAqB,CAAQ,CAAC;QAEpC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAA,mBAAY,EAAC,QAAQ,CAAC,CAAC;QAE9C,MAAM,IAAI,GAAG,MAAM,gBAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACpC,IAAI,kCAAO,IAAI,KAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE;SACxC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC;IACd,CAAC;CAAA;AAVD,gCAUC;AAED,SAAsB,eAAe,CAAC,KAAa;;QACjD,OAAO,gBAAM,CAAC,IAAI,CAAC,UAAU,CAAC;YAC5B,KAAK,EAAE;gBACL,KAAK;aACN;SACF,CAAC,CAAC;IACL,CAAC;CAAA;AAND,0CAMC;AAED,SAAsB,SAAS;;QAC7B,OAAO,gBAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC1B,MAAM,EAAE;gBACN,KAAK,EAAE,IAAI;gBACX,IAAI,EAAE,IAAI;gBACV,EAAE,EAAE,IAAI;aACT;SACF,CAAC,CAAC;IACL,CAAC;CAAA;AARD,8BAQC","sourcesContent":["import { hashPassword } from \"../../utils/hash\";\nimport prisma from \"../../utils/prisma\";\nimport { CreateUserInput } from \"./user.schema\";\n\nexport async function createUser(input: CreateUserInput) {\n const { password, ...rest } = input;\n\n const { hash, salt } = hashPassword(password);\n\n const user = await prisma.user.create({\n data: { ...rest, salt, password: hash },\n });\n\n return user;\n}\n\nexport async function findUserByEmail(email: string) {\n return prisma.user.findUnique({\n where: {\n email,\n },\n });\n}\n\nexport async function findUsers() {\n return prisma.user.findMany({\n select: {\n email: true,\n name: true,\n id: true,\n },\n });\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"4bc9ce49a4568d7e4f4fa478d5035cea525bc231","contentHash":"52496f2a2781c1ba6c41dddcbf8c2d70a006afb040f26383125d8b6ea497f16b"},"/Users/tom/projects/fastify-prisma/src/utils/prisma.ts":{"path":"/Users/tom/projects/fastify-prisma/src/utils/prisma.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":62}},"1":{"start":{"line":3,"column":17},"end":{"line":3,"column":42}},"2":{"start":{"line":4,"column":15},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":25}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1},"f":{},"b":{},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/utils/prisma.ts","sources":["/Users/tom/projects/fastify-prisma/src/utils/prisma.ts"],"names":[],"mappings":";;AAAA,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAElC,kBAAe,MAAM,CAAC","sourcesContent":["import { PrismaClient } from \"@prisma/client\";\n\nconst prisma = new PrismaClient();\n\nexport default prisma;\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"c69fe9cbbde4b378a26b8a069447fa3625dc00e3","contentHash":"80d41c56a3b244efbc8a4e20169d4a052f8030959835541eddf70ae31cea5ef4"},"/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":62}},"1":{"start":{"line":4,"column":0},"end":{"line":4,"column":44}},"2":{"start":{"line":5,"column":14},"end":{"line":5,"column":28}},"3":{"start":{"line":6,"column":22},"end":{"line":6,"column":44}},"4":{"start":{"line":7,"column":17},"end":{"line":15,"column":1}},"5":{"start":{"line":16,"column":25},"end":{"line":19,"column":10}},"6":{"start":{"line":20,"column":33},"end":{"line":20,"column":98}},"7":{"start":{"line":21,"column":20},"end":{"line":29,"column":2}},"8":{"start":{"line":30,"column":28},"end":{"line":32,"column":2}},"9":{"start":{"line":33,"column":0},"end":{"line":38,"column":61}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1},"f":{},"b":{},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts"],"names":[],"mappings":";;;;AAAA,6BAAwB;AACxB,6CAA+C;AAE/C,MAAM,QAAQ,GAAG;IACf,KAAK,EAAE,OAAC;SACL,MAAM,CAAC;QACN,cAAc,EAAE,mBAAmB;QACnC,kBAAkB,EAAE,wBAAwB;KAC7C,CAAC;SACD,KAAK,EAAE;IACV,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;CACjB,CAAC;AAEF,MAAM,gBAAgB,GAAG,OAAC,CAAC,MAAM,iCAC5B,QAAQ,KACX,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC;QACjB,cAAc,EAAE,sBAAsB;QACtC,kBAAkB,EAAE,2BAA2B;KAChD,CAAC,IACF,CAAC;AAEH,MAAM,wBAAwB,GAAG,OAAC,CAAC,MAAM,iBACvC,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,IACX,QAAQ,EACX,CAAC;AAEH,MAAM,WAAW,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3B,KAAK,EAAE,OAAC;SACL,MAAM,CAAC;QACN,cAAc,EAAE,mBAAmB;QACnC,kBAAkB,EAAE,wBAAwB;KAC7C,CAAC;SACD,KAAK,EAAE;IACV,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;CACrB,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC;IACnC,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC;AAMU,KAAiC,IAAA,8BAAgB,EAAC;IAC7D,gBAAgB;IAChB,wBAAwB;IACxB,WAAW;IACX,mBAAmB;CACpB,CAAC,EALsB,mBAAW,eAAE,YAAI,WAKtC","sourcesContent":["import { z } from \"zod\";\nimport { buildJsonSchemas } from \"fastify-zod\";\n\nconst userCore = {\n email: z\n .string({\n required_error: \"Email is required\",\n invalid_type_error: \"Email must be a string\",\n })\n .email(),\n name: z.string(),\n};\n\nconst createUserSchema = z.object({\n ...userCore,\n password: z.string({\n required_error: \"Password is required\",\n invalid_type_error: \"Password must be a string\",\n }),\n});\n\nconst createUserResponseSchema = z.object({\n id: z.number(),\n ...userCore,\n});\n\nconst loginSchema = z.object({\n email: z\n .string({\n required_error: \"Email is required\",\n invalid_type_error: \"Email must be a string\",\n })\n .email(),\n password: z.string(),\n});\n\nconst loginResponseSchema = z.object({\n accessToken: z.string(),\n});\n\nexport type CreateUserInput = z.infer;\n\nexport type LoginInput = z.infer;\n\nexport const { schemas: userSchemas, $ref } = buildJsonSchemas({\n createUserSchema,\n createUserResponseSchema,\n loginSchema,\n loginResponseSchema,\n});\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"3356e58fd8d4d400f63f77f05d77b62d9476670b","contentHash":"1313c1370c17ef3c37b2eb7c52fead2148c25a0e4a6f8f8496dff0471fcce014"},"/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":0},"end":{"line":11,"column":62}},"13":{"start":{"line":12,"column":29},"end":{"line":12,"column":60}},"14":{"start":{"line":13,"column":25},"end":{"line":13,"column":52}},"15":{"start":{"line":15,"column":4},"end":{"line":32,"column":7}},"16":{"start":{"line":16,"column":8},"end":{"line":24,"column":54}},"17":{"start":{"line":25,"column":8},"end":{"line":31,"column":52}},"18":{"start":{"line":34,"column":0},"end":{"line":34,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"productRoutes","decl":{"start":{"line":14,"column":9},"end":{"line":14,"column":22}},"loc":{"start":{"line":14,"column":31},"end":{"line":33,"column":1}},"line":14},"8":{"name":"(anonymous_8)","decl":{"start":{"line":15,"column":43},"end":{"line":15,"column":44}},"loc":{"start":{"line":15,"column":56},"end":{"line":32,"column":5}},"line":15}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8}},"s":{"0":1,"1":0,"2":0,"3":3,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":3,"11":3,"12":1,"13":1,"14":1,"15":3,"16":3,"17":3,"18":1},"f":{"0":3,"1":0,"2":0,"3":3,"4":0,"5":0,"6":3,"7":3,"8":3},"b":{"0":[1,1,1],"1":[0,0],"2":[3,3],"3":[3,0],"4":[3,3]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts"],"names":[],"mappings":";;;;;;;;;;;AACA,6DAAgF;AAChF,qDAAwC;AAExC,SAAe,aAAa,CAAC,MAAuB;;QAClD,MAAM,CAAC,IAAI,CACT,GAAG,EACH;YACE,UAAU,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC;YACjC,MAAM,EAAE;gBACN,IAAI,EAAE,IAAA,qBAAI,EAAC,qBAAqB,CAAC;gBACjC,QAAQ,EAAE;oBACR,GAAG,EAAE,IAAA,qBAAI,EAAC,uBAAuB,CAAC;iBACnC;aACF;SACF,EACD,yCAAoB,CACrB,CAAC;QAEF,MAAM,CAAC,GAAG,CACR,GAAG,EACH;YACE,MAAM,EAAE;gBACN,QAAQ,EAAE;oBACR,GAAG,EAAE,IAAA,qBAAI,EAAC,wBAAwB,CAAC;iBACpC;aACF;SACF,EAED,uCAAkB,CACnB,CAAC;IACJ,CAAC;CAAA;AAED,kBAAe,aAAa,CAAC","sourcesContent":["import { FastifyInstance } from \"fastify\";\nimport { createProductHandler, getProductsHandler } from \"./product.controller\";\nimport { $ref } from \"./product.schema\";\n\nasync function productRoutes(server: FastifyInstance) {\n server.post(\n \"/\",\n {\n preHandler: [server.authenticate],\n schema: {\n body: $ref(\"createProductSchema\"),\n response: {\n 201: $ref(\"productResponseSchema\"),\n },\n },\n },\n createProductHandler\n );\n\n server.get(\n \"/\",\n {\n schema: {\n response: {\n 200: $ref(\"productsResponseSchema\"),\n },\n },\n },\n\n getProductsHandler\n );\n}\n\nexport default productRoutes;\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"9c18e800eee1bdea952b46ba9cff51c35f9e8a9e","contentHash":"21cc167db4a9bbcd6c0730e926a4e2dd2a450f37e7a99d1822b34ff430cb6e72"},"/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":0},"end":{"line":11,"column":62}},"13":{"start":{"line":12,"column":0},"end":{"line":12,"column":67}},"14":{"start":{"line":13,"column":26},"end":{"line":13,"column":54}},"15":{"start":{"line":15,"column":4},"end":{"line":18,"column":7}},"16":{"start":{"line":16,"column":24},"end":{"line":16,"column":144}},"17":{"start":{"line":17,"column":8},"end":{"line":17,"column":23}},"18":{"start":{"line":20,"column":0},"end":{"line":20,"column":52}},"19":{"start":{"line":22,"column":4},"end":{"line":25,"column":7}},"20":{"start":{"line":23,"column":25},"end":{"line":23,"column":67}},"21":{"start":{"line":24,"column":8},"end":{"line":24,"column":24}},"22":{"start":{"line":27,"column":0},"end":{"line":27,"column":48}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"createProductHandler","decl":{"start":{"line":14,"column":9},"end":{"line":14,"column":29}},"loc":{"start":{"line":14,"column":39},"end":{"line":19,"column":1}},"line":14},"8":{"name":"(anonymous_8)","decl":{"start":{"line":15,"column":43},"end":{"line":15,"column":44}},"loc":{"start":{"line":15,"column":56},"end":{"line":18,"column":5}},"line":15},"9":{"name":"getProductsHandler","decl":{"start":{"line":21,"column":9},"end":{"line":21,"column":27}},"loc":{"start":{"line":21,"column":30},"end":{"line":26,"column":1}},"line":21},"10":{"name":"(anonymous_10)","decl":{"start":{"line":22,"column":43},"end":{"line":22,"column":44}},"loc":{"start":{"line":22,"column":56},"end":{"line":25,"column":5}},"line":22}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":1,"13":1,"14":1,"15":0,"16":0,"17":0,"18":1,"19":0,"20":0,"21":0,"22":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"b":{"0":[1,1,1],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA,uDAA+D;AAE/D,SAAsB,oBAAoB,CACxC,OAEE;;QAEF,MAAM,OAAO,GAAG,MAAM,IAAA,+BAAa,kCAC9B,OAAO,CAAC,IAAI,KACf,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IACxB,CAAC;QAEH,OAAO,OAAO,CAAC;IACjB,CAAC;CAAA;AAXD,oDAWC;AAED,SAAsB,kBAAkB;;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAA,6BAAW,GAAE,CAAC;QAErC,OAAO,QAAQ,CAAC;IAClB,CAAC;CAAA;AAJD,gDAIC","sourcesContent":["import { FastifyReply, FastifyRequest } from \"fastify\";\nimport { CreateProductInput } from \"./product.schema\";\nimport { createProduct, getProducts } from \"./product.service\";\n\nexport async function createProductHandler(\n request: FastifyRequest<{\n Body: CreateProductInput;\n }>\n) {\n const product = await createProduct({\n ...request.body,\n ownerId: request.user.id,\n });\n\n return product;\n}\n\nexport async function getProductsHandler() {\n const products = await getProducts();\n\n return products;\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2805c57ec3f7a13889daa7828ab38193979150be","contentHash":"528b19fa72a46ede7c7c8633e6a86c55d4a77c0b6c3c48655a4229ccf4818ba4"},"/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":22},"end":{"line":13,"column":1}},"13":{"start":{"line":12,"column":4},"end":{"line":12,"column":62}},"14":{"start":{"line":14,"column":0},"end":{"line":14,"column":62}},"15":{"start":{"line":15,"column":0},"end":{"line":15,"column":53}},"16":{"start":{"line":16,"column":17},"end":{"line":16,"column":63}},"17":{"start":{"line":18,"column":4},"end":{"line":22,"column":7}},"18":{"start":{"line":19,"column":8},"end":{"line":21,"column":11}},"19":{"start":{"line":24,"column":0},"end":{"line":24,"column":38}},"20":{"start":{"line":26,"column":4},"end":{"line":41,"column":7}},"21":{"start":{"line":43,"column":0},"end":{"line":43,"column":34}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":56},"end":{"line":11,"column":57}},"loc":{"start":{"line":11,"column":71},"end":{"line":13,"column":1}},"line":11},"8":{"name":"createProduct","decl":{"start":{"line":17,"column":9},"end":{"line":17,"column":22}},"loc":{"start":{"line":17,"column":29},"end":{"line":23,"column":1}},"line":17},"9":{"name":"(anonymous_9)","decl":{"start":{"line":18,"column":43},"end":{"line":18,"column":44}},"loc":{"start":{"line":18,"column":56},"end":{"line":22,"column":5}},"line":18},"10":{"name":"getProducts","decl":{"start":{"line":25,"column":9},"end":{"line":25,"column":20}},"loc":{"start":{"line":25,"column":23},"end":{"line":42,"column":1}},"line":25}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8},"5":{"loc":{"start":{"line":11,"column":22},"end":{"line":13,"column":1}},"type":"binary-expr","locations":[{"start":{"line":11,"column":23},"end":{"line":11,"column":27}},{"start":{"line":11,"column":31},"end":{"line":11,"column":51}},{"start":{"line":11,"column":56},"end":{"line":13,"column":1}}],"line":11},"6":{"loc":{"start":{"line":12,"column":11},"end":{"line":12,"column":61}},"type":"cond-expr","locations":[{"start":{"line":12,"column":37},"end":{"line":12,"column":40}},{"start":{"line":12,"column":43},"end":{"line":12,"column":61}}],"line":12},"7":{"loc":{"start":{"line":12,"column":12},"end":{"line":12,"column":33}},"type":"binary-expr","locations":[{"start":{"line":12,"column":12},"end":{"line":12,"column":15}},{"start":{"line":12,"column":19},"end":{"line":12,"column":33}}],"line":12}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":1,"13":1,"14":1,"15":1,"16":1,"17":0,"18":0,"19":1,"20":0,"21":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":1,"8":0,"9":0,"10":0},"b":{"0":[1,1,1],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[1,1,1],"6":[1,0],"7":[1,1]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,gEAAwC;AAGxC,SAAsB,aAAa,CACjC,IAA8C;;QAE9C,OAAO,gBAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YAC3B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;CAAA;AAND,sCAMC;AAED,SAAgB,WAAW;IACzB,OAAO,gBAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC7B,MAAM,EAAE;YACN,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI;YACX,EAAE,EAAE,IAAI;YACR,SAAS,EAAE,IAAI;YACf,SAAS,EAAE,IAAI;YACf,KAAK,EAAE;gBACL,MAAM,EAAE;oBACN,IAAI,EAAE,IAAI;oBACV,EAAE,EAAE,IAAI;iBACT;aACF;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAjBD,kCAiBC","sourcesContent":["import prisma from \"../../utils/prisma\";\nimport { CreateProductInput } from \"./product.schema\";\n\nexport async function createProduct(\n data: CreateProductInput & { ownerId: number }\n) {\n return prisma.product.create({\n data,\n });\n}\n\nexport function getProducts() {\n return prisma.product.findMany({\n select: {\n content: true,\n title: true,\n price: true,\n id: true,\n createdAt: true,\n updatedAt: true,\n owner: {\n select: {\n name: true,\n id: true,\n },\n },\n },\n });\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"4d893c9a2b4373e742772417fd73f7ae76ad1dbf","contentHash":"ce38dd022b459ace479469409183785096b20f0168b9928abc13c194606d4e68"},"/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":62}},"1":{"start":{"line":4,"column":0},"end":{"line":4,"column":47}},"2":{"start":{"line":5,"column":14},"end":{"line":5,"column":28}},"3":{"start":{"line":6,"column":22},"end":{"line":6,"column":44}},"4":{"start":{"line":7,"column":21},"end":{"line":11,"column":1}},"5":{"start":{"line":12,"column":25},"end":{"line":16,"column":1}},"6":{"start":{"line":17,"column":28},"end":{"line":17,"column":75}},"7":{"start":{"line":18,"column":30},"end":{"line":18,"column":110}},"8":{"start":{"line":19,"column":31},"end":{"line":19,"column":67}},"9":{"start":{"line":20,"column":0},"end":{"line":24,"column":64}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1},"f":{},"b":{},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts"],"names":[],"mappings":";;;;AAAA,6BAAwB;AACxB,6CAA+C;AAE/C,MAAM,YAAY,GAAG;IACnB,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;IACjB,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;IACjB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC;AAEF,MAAM,gBAAgB,GAAG;IACvB,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE;IACd,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;IACrB,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;CACtB,CAAC;AAEF,MAAM,mBAAmB,GAAG,OAAC,CAAC,MAAM,mBAC/B,YAAY,EACf,CAAC;AAEH,MAAM,qBAAqB,GAAG,OAAC,CAAC,MAAM,iCACjC,YAAY,GACZ,gBAAgB,EACnB,CAAC;AAEH,MAAM,sBAAsB,GAAG,OAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;AAIjD,KAAoC,IAAA,8BAAgB,EAAC;IAChE,mBAAmB;IACnB,qBAAqB;IACrB,sBAAsB;CACvB,CAAC,EAJsB,sBAAc,eAAE,YAAI,WAIzC","sourcesContent":["import { z } from \"zod\";\nimport { buildJsonSchemas } from \"fastify-zod\";\n\nconst productInput = {\n title: z.string(),\n price: z.number(),\n content: z.string().optional(),\n};\n\nconst productGenerated = {\n id: z.number(),\n createdAt: z.string(),\n updatedAt: z.string(),\n};\n\nconst createProductSchema = z.object({\n ...productInput,\n});\n\nconst productResponseSchema = z.object({\n ...productInput,\n ...productGenerated,\n});\n\nconst productsResponseSchema = z.array(productResponseSchema);\n\nexport type CreateProductInput = z.infer;\n\nexport const { schemas: productSchemas, $ref } = buildJsonSchemas({\n createProductSchema,\n productResponseSchema,\n productsResponseSchema,\n});\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"c5c6a36746e42423277a378c4a40a4007838c18f","contentHash":"2fb46a38bda61d7da225c158a3c31ab965138f872b82c5f3e2af88f580d92c5e"}} -------------------------------------------------------------------------------- /.nyc_output/46549699-3d4c-40cc-b68f-7a5d8d57f54e.json: -------------------------------------------------------------------------------- 1 | {"/Users/tom/projects/fastify-prisma/src/server.ts":{"path":"/Users/tom/projects/fastify-prisma/src/server.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":22},"end":{"line":13,"column":1}},"13":{"start":{"line":12,"column":4},"end":{"line":12,"column":62}},"14":{"start":{"line":14,"column":0},"end":{"line":14,"column":62}},"15":{"start":{"line":15,"column":18},"end":{"line":15,"column":53}},"16":{"start":{"line":16,"column":22},"end":{"line":16,"column":61}},"17":{"start":{"line":17,"column":26},"end":{"line":17,"column":69}},"18":{"start":{"line":18,"column":22},"end":{"line":18,"column":44}},"19":{"start":{"line":19,"column":21},"end":{"line":19,"column":74}},"20":{"start":{"line":20,"column":24},"end":{"line":20,"column":83}},"21":{"start":{"line":21,"column":22},"end":{"line":21,"column":59}},"22":{"start":{"line":22,"column":25},"end":{"line":22,"column":68}},"23":{"start":{"line":23,"column":23},"end":{"line":23,"column":49}},"24":{"start":{"line":25,"column":19},"end":{"line":25,"column":43}},"25":{"start":{"line":26,"column":4},"end":{"line":28,"column":7}},"26":{"start":{"line":29,"column":4},"end":{"line":36,"column":8}},"27":{"start":{"line":29,"column":56},"end":{"line":36,"column":6}},"28":{"start":{"line":30,"column":8},"end":{"line":35,"column":9}},"29":{"start":{"line":31,"column":12},"end":{"line":31,"column":38}},"30":{"start":{"line":34,"column":12},"end":{"line":34,"column":33}},"31":{"start":{"line":37,"column":4},"end":{"line":41,"column":7}},"32":{"start":{"line":38,"column":8},"end":{"line":40,"column":11}},"33":{"start":{"line":39,"column":12},"end":{"line":39,"column":36}},"34":{"start":{"line":42,"column":4},"end":{"line":45,"column":7}},"35":{"start":{"line":43,"column":8},"end":{"line":43,"column":29}},"36":{"start":{"line":44,"column":8},"end":{"line":44,"column":22}},"37":{"start":{"line":46,"column":4},"end":{"line":48,"column":5}},"38":{"start":{"line":47,"column":8},"end":{"line":47,"column":33}},"39":{"start":{"line":49,"column":4},"end":{"line":60,"column":8}},"40":{"start":{"line":61,"column":4},"end":{"line":61,"column":67}},"41":{"start":{"line":62,"column":4},"end":{"line":62,"column":73}},"42":{"start":{"line":63,"column":4},"end":{"line":63,"column":18}},"43":{"start":{"line":65,"column":0},"end":{"line":65,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":56},"end":{"line":11,"column":57}},"loc":{"start":{"line":11,"column":71},"end":{"line":13,"column":1}},"line":11},"8":{"name":"buildServer","decl":{"start":{"line":24,"column":9},"end":{"line":24,"column":20}},"loc":{"start":{"line":24,"column":23},"end":{"line":64,"column":1}},"line":24},"9":{"name":"(anonymous_9)","decl":{"start":{"line":29,"column":36},"end":{"line":29,"column":37}},"loc":{"start":{"line":29,"column":56},"end":{"line":36,"column":6}},"line":29},"10":{"name":"(anonymous_10)","decl":{"start":{"line":29,"column":88},"end":{"line":29,"column":89}},"loc":{"start":{"line":29,"column":101},"end":{"line":36,"column":5}},"line":29},"11":{"name":"(anonymous_11)","decl":{"start":{"line":37,"column":31},"end":{"line":37,"column":32}},"loc":{"start":{"line":37,"column":43},"end":{"line":41,"column":5}},"line":37},"12":{"name":"(anonymous_12)","decl":{"start":{"line":38,"column":47},"end":{"line":38,"column":48}},"loc":{"start":{"line":38,"column":60},"end":{"line":40,"column":9}},"line":38},"13":{"name":"(anonymous_13)","decl":{"start":{"line":42,"column":33},"end":{"line":42,"column":34}},"loc":{"start":{"line":42,"column":55},"end":{"line":45,"column":5}},"line":42}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8},"5":{"loc":{"start":{"line":11,"column":22},"end":{"line":13,"column":1}},"type":"binary-expr","locations":[{"start":{"line":11,"column":23},"end":{"line":11,"column":27}},{"start":{"line":11,"column":31},"end":{"line":11,"column":51}},{"start":{"line":11,"column":56},"end":{"line":13,"column":1}}],"line":11},"6":{"loc":{"start":{"line":12,"column":11},"end":{"line":12,"column":61}},"type":"cond-expr","locations":[{"start":{"line":12,"column":37},"end":{"line":12,"column":40}},{"start":{"line":12,"column":43},"end":{"line":12,"column":61}}],"line":12},"7":{"loc":{"start":{"line":12,"column":12},"end":{"line":12,"column":33}},"type":"binary-expr","locations":[{"start":{"line":12,"column":12},"end":{"line":12,"column":15}},{"start":{"line":12,"column":19},"end":{"line":12,"column":33}}],"line":12}},"s":{"0":1,"1":0,"2":0,"3":1,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":1,"11":1,"12":1,"13":5,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":1,"24":1,"25":1,"26":1,"27":0,"28":0,"29":0,"30":0,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":1,"38":7,"39":1,"40":1,"41":1,"42":1,"43":1},"f":{"0":1,"1":0,"2":0,"3":1,"4":0,"5":0,"6":1,"7":5,"8":1,"9":0,"10":0,"11":1,"12":1,"13":1},"b":{"0":[1,1,1],"1":[0,0],"2":[1,1],"3":[1,0],"4":[1,1],"5":[1,1,1],"6":[2,3],"7":[5,5]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/server.ts","sources":["/Users/tom/projects/fastify-prisma/src/server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,sDAAgE;AAChE,8DAAwC;AACxC,sEAAsC;AACtC,6CAA8C;AAC9C,2EAAmD;AACnD,oFAA4D;AAC5D,4DAAyD;AACzD,qEAAkE;AAClE,kDAA0C;AAqB1C,SAAS,WAAW;IAClB,MAAM,MAAM,GAAG,IAAA,iBAAO,GAAE,CAAC;IAEzB,MAAM,CAAC,QAAQ,CAAC,qBAAI,EAAE;QACpB,MAAM,EAAE,yCAAyC;KAClD,CAAC,CAAC;IAEH,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,CAAO,OAAuB,EAAE,KAAmB,EAAE,EAAE;QACrD,IAAI;YACF,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;SAC3B;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACtB;IACH,CAAC,CAAA,CACF,CAAC;IAEF,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE;;YACzB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1B,CAAC;KAAA,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAChD,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACrB,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,yBAAW,EAAE,GAAG,+BAAc,CAAC,EAAE;QACxD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;KAC1B;IAED,MAAM,CAAC,QAAQ,CACb,yBAAO,EACP,IAAA,6BAAe,EAAC;QACd,WAAW,EAAE,OAAO;QACpB,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,IAAI;QACf,OAAO,EAAE;YACP,IAAI,EAAE;gBACJ,KAAK,EAAE,aAAa;gBACpB,WAAW,EAAE,uBAAuB;gBACpC,OAAO,EAAP,sBAAO;aACR;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,QAAQ,CAAC,oBAAU,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACrD,MAAM,CAAC,QAAQ,CAAC,uBAAa,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;IAE3D,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kBAAe,WAAW,CAAC","sourcesContent":["import Fastify, { FastifyRequest, FastifyReply } from \"fastify\";\nimport fjwt, { JWT } from \"fastify-jwt\";\nimport swagger from \"fastify-swagger\";\nimport { withRefResolver } from \"fastify-zod\";\nimport userRoutes from \"./modules/user/user.route\";\nimport productRoutes from \"./modules/product/product.route\";\nimport { userSchemas } from \"./modules/user/user.schema\";\nimport { productSchemas } from \"./modules/product/product.schema\";\nimport { version } from \"../package.json\";\n\ndeclare module \"fastify\" {\n interface FastifyRequest {\n jwt: JWT;\n }\n export interface FastifyInstance {\n authenticate: any;\n }\n}\n\ndeclare module \"fastify-jwt\" {\n interface FastifyJWT {\n user: {\n id: number;\n email: string;\n name: string;\n };\n }\n}\n\nfunction buildServer() {\n const server = Fastify();\n\n server.register(fjwt, {\n secret: \"ndkandnan78duy9sau87dbndsa89u7dsy789adb\",\n });\n\n server.decorate(\n \"authenticate\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n try {\n await request.jwtVerify();\n } catch (e) {\n return reply.send(e);\n }\n }\n );\n\n server.get(\"/healthcheck\", async function () {\n return { status: \"OK\" };\n });\n\n server.addHook(\"preHandler\", (req, reply, next) => {\n req.jwt = server.jwt;\n return next();\n });\n\n for (const schema of [...userSchemas, ...productSchemas]) {\n server.addSchema(schema);\n }\n\n server.register(\n swagger,\n withRefResolver({\n routePrefix: \"/docs\",\n exposeRoute: true,\n staticCSP: true,\n openapi: {\n info: {\n title: \"Fastify API\",\n description: \"API for some products\",\n version,\n },\n },\n })\n );\n\n server.register(userRoutes, { prefix: \"api/users\" });\n server.register(productRoutes, { prefix: \"api/products\" });\n\n return server;\n}\n\nexport default buildServer;\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d110024f020ad2420cc48799519f114571270536","contentHash":"af2f7fa46fa7406659b83a18607f97c346aa47e00d1940e8fbe948e06fb58dac"},"/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":0},"end":{"line":11,"column":62}},"13":{"start":{"line":12,"column":26},"end":{"line":12,"column":54}},"14":{"start":{"line":13,"column":22},"end":{"line":13,"column":46}},"15":{"start":{"line":15,"column":4},"end":{"line":35,"column":7}},"16":{"start":{"line":16,"column":8},"end":{"line":23,"column":50}},"17":{"start":{"line":24,"column":8},"end":{"line":31,"column":43}},"18":{"start":{"line":32,"column":8},"end":{"line":34,"column":46}},"19":{"start":{"line":37,"column":0},"end":{"line":37,"column":29}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"userRoutes","decl":{"start":{"line":14,"column":9},"end":{"line":14,"column":19}},"loc":{"start":{"line":14,"column":28},"end":{"line":36,"column":1}},"line":14},"8":{"name":"(anonymous_8)","decl":{"start":{"line":15,"column":43},"end":{"line":15,"column":44}},"loc":{"start":{"line":15,"column":56},"end":{"line":35,"column":5}},"line":15}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8}},"s":{"0":1,"1":0,"2":0,"3":1,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1},"f":{"0":1,"1":0,"2":0,"3":1,"4":0,"5":0,"6":1,"7":1,"8":1},"b":{"0":[1,1,1],"1":[0,0],"2":[1,1],"3":[1,0],"4":[1,1]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/user/user.route.ts"],"names":[],"mappings":";;;;;;;;;;;AACA,uDAI2B;AAC3B,+CAAqC;AAErC,SAAe,UAAU,CAAC,MAAuB;;QAC/C,MAAM,CAAC,IAAI,CACT,GAAG,EACH;YACE,MAAM,EAAE;gBACN,IAAI,EAAE,IAAA,kBAAI,EAAC,kBAAkB,CAAC;gBAC9B,QAAQ,EAAE;oBACR,GAAG,EAAE,IAAA,kBAAI,EAAC,0BAA0B,CAAC;iBACtC;aACF;SACF,EACD,qCAAmB,CACpB,CAAC;QAEF,MAAM,CAAC,IAAI,CACT,QAAQ,EACR;YACE,MAAM,EAAE;gBACN,IAAI,EAAE,IAAA,kBAAI,EAAC,aAAa,CAAC;gBACzB,QAAQ,EAAE;oBACR,GAAG,EAAE,IAAA,kBAAI,EAAC,qBAAqB,CAAC;iBACjC;aACF;SACF,EACD,8BAAY,CACb,CAAC;QAEF,MAAM,CAAC,GAAG,CACR,GAAG,EACH;YACE,UAAU,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC;SAClC,EACD,iCAAe,CAChB,CAAC;IACJ,CAAC;CAAA;AAED,kBAAe,UAAU,CAAC","sourcesContent":["import { FastifyInstance } from \"fastify\";\nimport {\n loginHandler,\n registerUserHandler,\n getUsersHandler,\n} from \"./user.controller\";\nimport { $ref } from \"./user.schema\";\n\nasync function userRoutes(server: FastifyInstance) {\n server.post(\n \"/\",\n {\n schema: {\n body: $ref(\"createUserSchema\"),\n response: {\n 201: $ref(\"createUserResponseSchema\"),\n },\n },\n },\n registerUserHandler\n );\n\n server.post(\n \"/login\",\n {\n schema: {\n body: $ref(\"loginSchema\"),\n response: {\n 200: $ref(\"loginResponseSchema\"),\n },\n },\n },\n loginHandler\n );\n\n server.get(\n \"/\",\n {\n preHandler: [server.authenticate],\n },\n getUsersHandler\n );\n}\n\nexport default userRoutes;\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"fcf266702283962cfc6c149b84a59ef5bc8e9cf1","contentHash":"7d4d49ab72c99eb67162f99489d30c0ee18a78071dffa23f3cdf52299a9d45ae"},"/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":13},"end":{"line":21,"column":1}},"13":{"start":{"line":12,"column":12},"end":{"line":12,"column":14}},"14":{"start":{"line":13,"column":4},"end":{"line":14,"column":20}},"15":{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},"16":{"start":{"line":14,"column":8},"end":{"line":14,"column":20}},"17":{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},"18":{"start":{"line":16,"column":8},"end":{"line":19,"column":9}},"19":{"start":{"line":16,"column":21},"end":{"line":16,"column":22}},"20":{"start":{"line":16,"column":28},"end":{"line":16,"column":59}},"21":{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},"22":{"start":{"line":18,"column":16},"end":{"line":18,"column":34}},"23":{"start":{"line":20,"column":4},"end":{"line":20,"column":13}},"24":{"start":{"line":22,"column":0},"end":{"line":22,"column":62}},"25":{"start":{"line":23,"column":0},"end":{"line":23,"column":86}},"26":{"start":{"line":24,"column":15},"end":{"line":24,"column":42}},"27":{"start":{"line":25,"column":23},"end":{"line":25,"column":48}},"28":{"start":{"line":27,"column":4},"end":{"line":37,"column":7}},"29":{"start":{"line":28,"column":21},"end":{"line":28,"column":33}},"30":{"start":{"line":29,"column":8},"end":{"line":36,"column":9}},"31":{"start":{"line":30,"column":25},"end":{"line":30,"column":67}},"32":{"start":{"line":31,"column":12},"end":{"line":31,"column":46}},"33":{"start":{"line":34,"column":12},"end":{"line":34,"column":27}},"34":{"start":{"line":35,"column":12},"end":{"line":35,"column":43}},"35":{"start":{"line":39,"column":0},"end":{"line":39,"column":50}},"36":{"start":{"line":41,"column":4},"end":{"line":64,"column":7}},"37":{"start":{"line":42,"column":21},"end":{"line":42,"column":33}},"38":{"start":{"line":44,"column":21},"end":{"line":44,"column":74}},"39":{"start":{"line":45,"column":8},"end":{"line":49,"column":9}},"40":{"start":{"line":46,"column":12},"end":{"line":48,"column":15}},"41":{"start":{"line":51,"column":32},"end":{"line":55,"column":10}},"42":{"start":{"line":56,"column":8},"end":{"line":60,"column":9}},"43":{"start":{"line":57,"column":39},"end":{"line":57,"column":43}},"44":{"start":{"line":57,"column":52},"end":{"line":57,"column":86}},"45":{"start":{"line":59,"column":12},"end":{"line":59,"column":59}},"46":{"start":{"line":61,"column":8},"end":{"line":63,"column":11}},"47":{"start":{"line":66,"column":0},"end":{"line":66,"column":36}},"48":{"start":{"line":68,"column":4},"end":{"line":71,"column":7}},"49":{"start":{"line":69,"column":22},"end":{"line":69,"column":59}},"50":{"start":{"line":70,"column":8},"end":{"line":70,"column":21}},"51":{"start":{"line":73,"column":0},"end":{"line":73,"column":42}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":38},"end":{"line":11,"column":39}},"loc":{"start":{"line":11,"column":54},"end":{"line":21,"column":1}},"line":11},"8":{"name":"registerUserHandler","decl":{"start":{"line":26,"column":9},"end":{"line":26,"column":28}},"loc":{"start":{"line":26,"column":45},"end":{"line":38,"column":1}},"line":26},"9":{"name":"(anonymous_9)","decl":{"start":{"line":27,"column":43},"end":{"line":27,"column":44}},"loc":{"start":{"line":27,"column":56},"end":{"line":37,"column":5}},"line":27},"10":{"name":"loginHandler","decl":{"start":{"line":40,"column":9},"end":{"line":40,"column":21}},"loc":{"start":{"line":40,"column":38},"end":{"line":65,"column":1}},"line":40},"11":{"name":"(anonymous_11)","decl":{"start":{"line":41,"column":43},"end":{"line":41,"column":44}},"loc":{"start":{"line":41,"column":56},"end":{"line":64,"column":5}},"line":41},"12":{"name":"getUsersHandler","decl":{"start":{"line":67,"column":9},"end":{"line":67,"column":24}},"loc":{"start":{"line":67,"column":27},"end":{"line":72,"column":1}},"line":67},"13":{"name":"(anonymous_13)","decl":{"start":{"line":68,"column":43},"end":{"line":68,"column":44}},"loc":{"start":{"line":68,"column":56},"end":{"line":71,"column":5}},"line":68}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8},"5":{"loc":{"start":{"line":11,"column":13},"end":{"line":21,"column":1}},"type":"binary-expr","locations":[{"start":{"line":11,"column":14},"end":{"line":11,"column":18}},{"start":{"line":11,"column":22},"end":{"line":11,"column":33}},{"start":{"line":11,"column":38},"end":{"line":21,"column":1}}],"line":11},"6":{"loc":{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},"type":"if","locations":[{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},{"start":{"line":13,"column":21},"end":{"line":14,"column":20}}],"line":13},"7":{"loc":{"start":{"line":13,"column":25},"end":{"line":13,"column":87}},"type":"binary-expr","locations":[{"start":{"line":13,"column":25},"end":{"line":13,"column":67}},{"start":{"line":13,"column":71},"end":{"line":13,"column":87}}],"line":13},"8":{"loc":{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},{"start":{"line":15,"column":4},"end":{"line":19,"column":9}}],"line":15},"9":{"loc":{"start":{"line":15,"column":8},"end":{"line":15,"column":71}},"type":"binary-expr","locations":[{"start":{"line":15,"column":8},"end":{"line":15,"column":17}},{"start":{"line":15,"column":21},"end":{"line":15,"column":71}}],"line":15},"10":{"loc":{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},"type":"if","locations":[{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},{"start":{"line":17,"column":12},"end":{"line":18,"column":34}}],"line":17},"11":{"loc":{"start":{"line":17,"column":16},"end":{"line":17,"column":90}},"type":"binary-expr","locations":[{"start":{"line":17,"column":16},"end":{"line":17,"column":35}},{"start":{"line":17,"column":39},"end":{"line":17,"column":90}}],"line":17},"12":{"loc":{"start":{"line":45,"column":8},"end":{"line":49,"column":9}},"type":"if","locations":[{"start":{"line":45,"column":8},"end":{"line":49,"column":9}},{"start":{"line":45,"column":8},"end":{"line":49,"column":9}}],"line":45},"13":{"loc":{"start":{"line":56,"column":8},"end":{"line":60,"column":9}},"type":"if","locations":[{"start":{"line":56,"column":8},"end":{"line":60,"column":9}},{"start":{"line":56,"column":8},"end":{"line":60,"column":9}}],"line":56}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":1,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":1,"25":1,"26":1,"27":1,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":1,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":1,"48":0,"49":0,"50":0,"51":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0},"b":{"0":[1,1,1],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[1,1,1],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0,0]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/user/user.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AACA,2CAAkD;AAElD,iDAAwE;AAExE,SAAsB,mBAAmB,CACvC,OAEE,EACF,KAAmB;;QAEnB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAE1B,IAAI;YACF,MAAM,IAAI,GAAG,MAAM,IAAA,yBAAU,EAAC,IAAI,CAAC,CAAC;YAEpC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SACnC;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACf,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAChC;IACH,CAAC;CAAA;AAhBD,kDAgBC;AAED,SAAsB,YAAY,CAChC,OAEE,EACF,KAAmB;;QAEnB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAE1B,uBAAuB;QACvB,MAAM,IAAI,GAAG,MAAM,IAAA,8BAAe,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE/C,IAAI,CAAC,IAAI,EAAE;YACT,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC1B,OAAO,EAAE,2BAA2B;aACrC,CAAC,CAAC;SACJ;QAED,kBAAkB;QAClB,MAAM,eAAe,GAAG,IAAA,qBAAc,EAAC;YACrC,iBAAiB,EAAE,IAAI,CAAC,QAAQ;YAChC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,QAAQ;SACpB,CAAC,CAAC;QAEH,IAAI,eAAe,EAAE;YACnB,MAAM,EAAE,QAAQ,EAAE,IAAI,KAAc,IAAI,EAAb,IAAI,UAAK,IAAI,EAAlC,oBAA2B,CAAO,CAAC;YACzC,wBAAwB;YACxB,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SAChD;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,OAAO,EAAE,2BAA2B;SACrC,CAAC,CAAC;IACL,CAAC;CAAA;AAjCD,oCAiCC;AAED,SAAsB,eAAe;;QACnC,MAAM,KAAK,GAAG,MAAM,IAAA,wBAAS,GAAE,CAAC;QAEhC,OAAO,KAAK,CAAC;IACf,CAAC;CAAA;AAJD,0CAIC","sourcesContent":["import { FastifyReply, FastifyRequest } from \"fastify\";\nimport { verifyPassword } from \"../../utils/hash\";\nimport { CreateUserInput, LoginInput } from \"./user.schema\";\nimport { createUser, findUserByEmail, findUsers } from \"./user.service\";\n\nexport async function registerUserHandler(\n request: FastifyRequest<{\n Body: CreateUserInput;\n }>,\n reply: FastifyReply\n) {\n const body = request.body;\n\n try {\n const user = await createUser(body);\n\n return reply.code(201).send(user);\n } catch (e) {\n console.log(e);\n return reply.code(500).send(e);\n }\n}\n\nexport async function loginHandler(\n request: FastifyRequest<{\n Body: LoginInput;\n }>,\n reply: FastifyReply\n) {\n const body = request.body;\n\n // find a user by email\n const user = await findUserByEmail(body.email);\n\n if (!user) {\n return reply.code(401).send({\n message: \"Invalid email or password\",\n });\n }\n\n // verify password\n const correctPassword = verifyPassword({\n candidatePassword: body.password,\n salt: user.salt,\n hash: user.password,\n });\n\n if (correctPassword) {\n const { password, salt, ...rest } = user;\n // generate access token\n return { accessToken: request.jwt.sign(rest) };\n }\n\n return reply.code(401).send({\n message: \"Invalid email or password\",\n });\n}\n\nexport async function getUsersHandler() {\n const users = await findUsers();\n\n return users;\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"66390af8925f32e5101fd5f4c4d5b5db4544e3d1","contentHash":"a4d44072d26a5fb12cbb748def8fd41b639d96c5508a622593dde931d849d1fa"},"/Users/tom/projects/fastify-prisma/src/utils/hash.ts":{"path":"/Users/tom/projects/fastify-prisma/src/utils/hash.ts","statementMap":{"0":{"start":{"line":2,"column":22},"end":{"line":4,"column":1}},"1":{"start":{"line":3,"column":4},"end":{"line":3,"column":62}},"2":{"start":{"line":5,"column":0},"end":{"line":5,"column":62}},"3":{"start":{"line":6,"column":0},"end":{"line":6,"column":55}},"4":{"start":{"line":7,"column":17},"end":{"line":7,"column":51}},"5":{"start":{"line":14,"column":17},"end":{"line":14,"column":65}},"6":{"start":{"line":18,"column":17},"end":{"line":20,"column":24}},"7":{"start":{"line":21,"column":4},"end":{"line":21,"column":26}},"8":{"start":{"line":23,"column":0},"end":{"line":23,"column":36}},"9":{"start":{"line":29,"column":26},"end":{"line":31,"column":24}},"10":{"start":{"line":36,"column":4},"end":{"line":36,"column":34}},"11":{"start":{"line":38,"column":0},"end":{"line":38,"column":40}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":56},"end":{"line":2,"column":57}},"loc":{"start":{"line":2,"column":71},"end":{"line":4,"column":1}},"line":2},"1":{"name":"hashPassword","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":21}},"loc":{"start":{"line":8,"column":32},"end":{"line":22,"column":1}},"line":8},"2":{"name":"verifyPassword","decl":{"start":{"line":24,"column":9},"end":{"line":24,"column":23}},"loc":{"start":{"line":24,"column":60},"end":{"line":37,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":22},"end":{"line":4,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":23},"end":{"line":2,"column":27}},{"start":{"line":2,"column":31},"end":{"line":2,"column":51}},{"start":{"line":2,"column":56},"end":{"line":4,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":11},"end":{"line":3,"column":61}},"type":"cond-expr","locations":[{"start":{"line":3,"column":37},"end":{"line":3,"column":40}},{"start":{"line":3,"column":43},"end":{"line":3,"column":61}}],"line":3},"2":{"loc":{"start":{"line":3,"column":12},"end":{"line":3,"column":33}},"type":"binary-expr","locations":[{"start":{"line":3,"column":12},"end":{"line":3,"column":15}},{"start":{"line":3,"column":19},"end":{"line":3,"column":33}}],"line":3}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":1,"9":0,"10":0,"11":1},"f":{"0":1,"1":0,"2":0},"b":{"0":[1,1,1],"1":[0,1],"2":[1,1]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/utils/hash.ts","sources":["/Users/tom/projects/fastify-prisma/src/utils/hash.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAE5B,SAAgB,YAAY,CAAC,QAAgB;IAC3C;;;;OAIG;IACH,MAAM,IAAI,GAAG,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEpD;;OAEG;IACH,MAAM,IAAI,GAAG,gBAAM;SAChB,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,CAAC;SAC9C,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEnB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC;AAhBD,oCAgBC;AAED,SAAgB,cAAc,CAAC,EAC7B,iBAAiB,EACjB,IAAI,EACJ,IAAI,GAKL;IACC;;;OAGG;IACH,MAAM,aAAa,GAAG,gBAAM;SACzB,UAAU,CAAC,iBAAiB,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,CAAC;SACvD,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEnB;;;OAGG;IAEH,OAAO,aAAa,KAAK,IAAI,CAAC;AAChC,CAAC;AAvBD,wCAuBC","sourcesContent":["import crypto from \"crypto\";\n\nexport function hashPassword(password: string) {\n /*\n * Creating a unique salt for a particular user\n * Salt is a random bit of data added to the user's password\n * Salt means that every password's hash is going to be unique\n */\n const salt = crypto.randomBytes(16).toString(\"hex\");\n\n /*\n * Create a hash with 1000 iterations\n */\n const hash = crypto\n .pbkdf2Sync(password, salt, 1000, 64, \"sha512\")\n .toString(\"hex\");\n\n return { hash, salt };\n}\n\nexport function verifyPassword({\n candidatePassword,\n salt,\n hash,\n}: {\n candidatePassword: string;\n salt: string;\n hash: string;\n}) {\n /*\n * Create a hash with the salt from the user and the password\n * the user tried to login with\n */\n const candidateHash = crypto\n .pbkdf2Sync(candidatePassword, salt, 1000, 64, \"sha512\")\n .toString(\"hex\");\n\n /*\n * If the hash matches the hash we have stored for the user\n * then the candidate password is correct\n */\n\n return candidateHash === hash;\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"ea59f0a61b9dd5cc16f317308b72be3f944f36c6","contentHash":"c75bb33ff482332961e8a68862efd412f509cab5dea4eb2e136c472ed5fc7623"},"/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":13},"end":{"line":21,"column":1}},"13":{"start":{"line":12,"column":12},"end":{"line":12,"column":14}},"14":{"start":{"line":13,"column":4},"end":{"line":14,"column":20}},"15":{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},"16":{"start":{"line":14,"column":8},"end":{"line":14,"column":20}},"17":{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},"18":{"start":{"line":16,"column":8},"end":{"line":19,"column":9}},"19":{"start":{"line":16,"column":21},"end":{"line":16,"column":22}},"20":{"start":{"line":16,"column":28},"end":{"line":16,"column":59}},"21":{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},"22":{"start":{"line":18,"column":16},"end":{"line":18,"column":34}},"23":{"start":{"line":20,"column":4},"end":{"line":20,"column":13}},"24":{"start":{"line":22,"column":22},"end":{"line":24,"column":1}},"25":{"start":{"line":23,"column":4},"end":{"line":23,"column":62}},"26":{"start":{"line":25,"column":0},"end":{"line":25,"column":62}},"27":{"start":{"line":26,"column":0},"end":{"line":26,"column":74}},"28":{"start":{"line":27,"column":15},"end":{"line":27,"column":42}},"29":{"start":{"line":28,"column":17},"end":{"line":28,"column":63}},"30":{"start":{"line":30,"column":4},"end":{"line":37,"column":7}},"31":{"start":{"line":31,"column":29},"end":{"line":31,"column":34}},"32":{"start":{"line":31,"column":43},"end":{"line":31,"column":70}},"33":{"start":{"line":32,"column":31},"end":{"line":32,"column":65}},"34":{"start":{"line":33,"column":21},"end":{"line":35,"column":10}},"35":{"start":{"line":36,"column":8},"end":{"line":36,"column":20}},"36":{"start":{"line":39,"column":0},"end":{"line":39,"column":32}},"37":{"start":{"line":41,"column":4},"end":{"line":47,"column":7}},"38":{"start":{"line":42,"column":8},"end":{"line":46,"column":11}},"39":{"start":{"line":49,"column":0},"end":{"line":49,"column":42}},"40":{"start":{"line":51,"column":4},"end":{"line":59,"column":7}},"41":{"start":{"line":52,"column":8},"end":{"line":58,"column":11}},"42":{"start":{"line":61,"column":0},"end":{"line":61,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":38},"end":{"line":11,"column":39}},"loc":{"start":{"line":11,"column":54},"end":{"line":21,"column":1}},"line":11},"8":{"name":"(anonymous_8)","decl":{"start":{"line":22,"column":56},"end":{"line":22,"column":57}},"loc":{"start":{"line":22,"column":71},"end":{"line":24,"column":1}},"line":22},"9":{"name":"createUser","decl":{"start":{"line":29,"column":9},"end":{"line":29,"column":19}},"loc":{"start":{"line":29,"column":27},"end":{"line":38,"column":1}},"line":29},"10":{"name":"(anonymous_10)","decl":{"start":{"line":30,"column":43},"end":{"line":30,"column":44}},"loc":{"start":{"line":30,"column":56},"end":{"line":37,"column":5}},"line":30},"11":{"name":"findUserByEmail","decl":{"start":{"line":40,"column":9},"end":{"line":40,"column":24}},"loc":{"start":{"line":40,"column":32},"end":{"line":48,"column":1}},"line":40},"12":{"name":"(anonymous_12)","decl":{"start":{"line":41,"column":43},"end":{"line":41,"column":44}},"loc":{"start":{"line":41,"column":56},"end":{"line":47,"column":5}},"line":41},"13":{"name":"findUsers","decl":{"start":{"line":50,"column":9},"end":{"line":50,"column":18}},"loc":{"start":{"line":50,"column":21},"end":{"line":60,"column":1}},"line":50},"14":{"name":"(anonymous_14)","decl":{"start":{"line":51,"column":43},"end":{"line":51,"column":44}},"loc":{"start":{"line":51,"column":56},"end":{"line":59,"column":5}},"line":51}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8},"5":{"loc":{"start":{"line":11,"column":13},"end":{"line":21,"column":1}},"type":"binary-expr","locations":[{"start":{"line":11,"column":14},"end":{"line":11,"column":18}},{"start":{"line":11,"column":22},"end":{"line":11,"column":33}},{"start":{"line":11,"column":38},"end":{"line":21,"column":1}}],"line":11},"6":{"loc":{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},"type":"if","locations":[{"start":{"line":13,"column":21},"end":{"line":14,"column":20}},{"start":{"line":13,"column":21},"end":{"line":14,"column":20}}],"line":13},"7":{"loc":{"start":{"line":13,"column":25},"end":{"line":13,"column":87}},"type":"binary-expr","locations":[{"start":{"line":13,"column":25},"end":{"line":13,"column":67}},{"start":{"line":13,"column":71},"end":{"line":13,"column":87}}],"line":13},"8":{"loc":{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":19,"column":9}},{"start":{"line":15,"column":4},"end":{"line":19,"column":9}}],"line":15},"9":{"loc":{"start":{"line":15,"column":8},"end":{"line":15,"column":71}},"type":"binary-expr","locations":[{"start":{"line":15,"column":8},"end":{"line":15,"column":17}},{"start":{"line":15,"column":21},"end":{"line":15,"column":71}}],"line":15},"10":{"loc":{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},"type":"if","locations":[{"start":{"line":17,"column":12},"end":{"line":18,"column":34}},{"start":{"line":17,"column":12},"end":{"line":18,"column":34}}],"line":17},"11":{"loc":{"start":{"line":17,"column":16},"end":{"line":17,"column":90}},"type":"binary-expr","locations":[{"start":{"line":17,"column":16},"end":{"line":17,"column":35}},{"start":{"line":17,"column":39},"end":{"line":17,"column":90}}],"line":17},"12":{"loc":{"start":{"line":22,"column":22},"end":{"line":24,"column":1}},"type":"binary-expr","locations":[{"start":{"line":22,"column":23},"end":{"line":22,"column":27}},{"start":{"line":22,"column":31},"end":{"line":22,"column":51}},{"start":{"line":22,"column":56},"end":{"line":24,"column":1}}],"line":22},"13":{"loc":{"start":{"line":23,"column":11},"end":{"line":23,"column":61}},"type":"cond-expr","locations":[{"start":{"line":23,"column":37},"end":{"line":23,"column":40}},{"start":{"line":23,"column":43},"end":{"line":23,"column":61}}],"line":23},"14":{"loc":{"start":{"line":23,"column":12},"end":{"line":23,"column":33}},"type":"binary-expr","locations":[{"start":{"line":23,"column":12},"end":{"line":23,"column":15}},{"start":{"line":23,"column":19},"end":{"line":23,"column":33}}],"line":23}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":1,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":1,"25":1,"26":1,"27":1,"28":1,"29":1,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":1,"37":0,"38":0,"39":1,"40":0,"41":0,"42":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":1,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0},"b":{"0":[1,1,1],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[1,1,1],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[1,1,1],"13":[1,0],"14":[1,1]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/user/user.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAgD;AAChD,gEAAwC;AAGxC,SAAsB,UAAU,CAAC,KAAsB;;QACrD,MAAM,EAAE,QAAQ,KAAc,KAAK,EAAd,IAAI,UAAK,KAAK,EAA7B,YAAqB,CAAQ,CAAC;QAEpC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAA,mBAAY,EAAC,QAAQ,CAAC,CAAC;QAE9C,MAAM,IAAI,GAAG,MAAM,gBAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACpC,IAAI,kCAAO,IAAI,KAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE;SACxC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC;IACd,CAAC;CAAA;AAVD,gCAUC;AAED,SAAsB,eAAe,CAAC,KAAa;;QACjD,OAAO,gBAAM,CAAC,IAAI,CAAC,UAAU,CAAC;YAC5B,KAAK,EAAE;gBACL,KAAK;aACN;SACF,CAAC,CAAC;IACL,CAAC;CAAA;AAND,0CAMC;AAED,SAAsB,SAAS;;QAC7B,OAAO,gBAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC1B,MAAM,EAAE;gBACN,KAAK,EAAE,IAAI;gBACX,IAAI,EAAE,IAAI;gBACV,EAAE,EAAE,IAAI;aACT;SACF,CAAC,CAAC;IACL,CAAC;CAAA;AARD,8BAQC","sourcesContent":["import { hashPassword } from \"../../utils/hash\";\nimport prisma from \"../../utils/prisma\";\nimport { CreateUserInput } from \"./user.schema\";\n\nexport async function createUser(input: CreateUserInput) {\n const { password, ...rest } = input;\n\n const { hash, salt } = hashPassword(password);\n\n const user = await prisma.user.create({\n data: { ...rest, salt, password: hash },\n });\n\n return user;\n}\n\nexport async function findUserByEmail(email: string) {\n return prisma.user.findUnique({\n where: {\n email,\n },\n });\n}\n\nexport async function findUsers() {\n return prisma.user.findMany({\n select: {\n email: true,\n name: true,\n id: true,\n },\n });\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"4bc9ce49a4568d7e4f4fa478d5035cea525bc231","contentHash":"52496f2a2781c1ba6c41dddcbf8c2d70a006afb040f26383125d8b6ea497f16b"},"/Users/tom/projects/fastify-prisma/src/utils/prisma.ts":{"path":"/Users/tom/projects/fastify-prisma/src/utils/prisma.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":62}},"1":{"start":{"line":3,"column":17},"end":{"line":3,"column":42}},"2":{"start":{"line":4,"column":15},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":25}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1},"f":{},"b":{},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/utils/prisma.ts","sources":["/Users/tom/projects/fastify-prisma/src/utils/prisma.ts"],"names":[],"mappings":";;AAAA,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAElC,kBAAe,MAAM,CAAC","sourcesContent":["import { PrismaClient } from \"@prisma/client\";\n\nconst prisma = new PrismaClient();\n\nexport default prisma;\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"c69fe9cbbde4b378a26b8a069447fa3625dc00e3","contentHash":"80d41c56a3b244efbc8a4e20169d4a052f8030959835541eddf70ae31cea5ef4"},"/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":62}},"1":{"start":{"line":4,"column":0},"end":{"line":4,"column":44}},"2":{"start":{"line":5,"column":14},"end":{"line":5,"column":28}},"3":{"start":{"line":6,"column":22},"end":{"line":6,"column":44}},"4":{"start":{"line":7,"column":17},"end":{"line":15,"column":1}},"5":{"start":{"line":16,"column":25},"end":{"line":19,"column":10}},"6":{"start":{"line":20,"column":33},"end":{"line":20,"column":98}},"7":{"start":{"line":21,"column":20},"end":{"line":29,"column":2}},"8":{"start":{"line":30,"column":28},"end":{"line":32,"column":2}},"9":{"start":{"line":33,"column":0},"end":{"line":38,"column":61}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1},"f":{},"b":{},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/user/user.schema.ts"],"names":[],"mappings":";;;;AAAA,6BAAwB;AACxB,6CAA+C;AAE/C,MAAM,QAAQ,GAAG;IACf,KAAK,EAAE,OAAC;SACL,MAAM,CAAC;QACN,cAAc,EAAE,mBAAmB;QACnC,kBAAkB,EAAE,wBAAwB;KAC7C,CAAC;SACD,KAAK,EAAE;IACV,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;CACjB,CAAC;AAEF,MAAM,gBAAgB,GAAG,OAAC,CAAC,MAAM,iCAC5B,QAAQ,KACX,QAAQ,EAAE,OAAC,CAAC,MAAM,CAAC;QACjB,cAAc,EAAE,sBAAsB;QACtC,kBAAkB,EAAE,2BAA2B;KAChD,CAAC,IACF,CAAC;AAEH,MAAM,wBAAwB,GAAG,OAAC,CAAC,MAAM,iBACvC,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,IACX,QAAQ,EACX,CAAC;AAEH,MAAM,WAAW,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3B,KAAK,EAAE,OAAC;SACL,MAAM,CAAC;QACN,cAAc,EAAE,mBAAmB;QACnC,kBAAkB,EAAE,wBAAwB;KAC7C,CAAC;SACD,KAAK,EAAE;IACV,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;CACrB,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC;IACnC,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC;AAMU,KAAiC,IAAA,8BAAgB,EAAC;IAC7D,gBAAgB;IAChB,wBAAwB;IACxB,WAAW;IACX,mBAAmB;CACpB,CAAC,EALsB,mBAAW,eAAE,YAAI,WAKtC","sourcesContent":["import { z } from \"zod\";\nimport { buildJsonSchemas } from \"fastify-zod\";\n\nconst userCore = {\n email: z\n .string({\n required_error: \"Email is required\",\n invalid_type_error: \"Email must be a string\",\n })\n .email(),\n name: z.string(),\n};\n\nconst createUserSchema = z.object({\n ...userCore,\n password: z.string({\n required_error: \"Password is required\",\n invalid_type_error: \"Password must be a string\",\n }),\n});\n\nconst createUserResponseSchema = z.object({\n id: z.number(),\n ...userCore,\n});\n\nconst loginSchema = z.object({\n email: z\n .string({\n required_error: \"Email is required\",\n invalid_type_error: \"Email must be a string\",\n })\n .email(),\n password: z.string(),\n});\n\nconst loginResponseSchema = z.object({\n accessToken: z.string(),\n});\n\nexport type CreateUserInput = z.infer;\n\nexport type LoginInput = z.infer;\n\nexport const { schemas: userSchemas, $ref } = buildJsonSchemas({\n createUserSchema,\n createUserResponseSchema,\n loginSchema,\n loginResponseSchema,\n});\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"3356e58fd8d4d400f63f77f05d77b62d9476670b","contentHash":"1313c1370c17ef3c37b2eb7c52fead2148c25a0e4a6f8f8496dff0471fcce014"},"/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":0},"end":{"line":11,"column":62}},"13":{"start":{"line":12,"column":29},"end":{"line":12,"column":60}},"14":{"start":{"line":13,"column":25},"end":{"line":13,"column":52}},"15":{"start":{"line":15,"column":4},"end":{"line":32,"column":7}},"16":{"start":{"line":16,"column":8},"end":{"line":24,"column":54}},"17":{"start":{"line":25,"column":8},"end":{"line":31,"column":52}},"18":{"start":{"line":34,"column":0},"end":{"line":34,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"productRoutes","decl":{"start":{"line":14,"column":9},"end":{"line":14,"column":22}},"loc":{"start":{"line":14,"column":31},"end":{"line":33,"column":1}},"line":14},"8":{"name":"(anonymous_8)","decl":{"start":{"line":15,"column":43},"end":{"line":15,"column":44}},"loc":{"start":{"line":15,"column":56},"end":{"line":32,"column":5}},"line":15}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8}},"s":{"0":1,"1":0,"2":0,"3":1,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1},"f":{"0":1,"1":0,"2":0,"3":1,"4":0,"5":0,"6":1,"7":1,"8":1},"b":{"0":[1,1,1],"1":[0,0],"2":[1,1],"3":[1,0],"4":[1,1]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/product/product.route.ts"],"names":[],"mappings":";;;;;;;;;;;AACA,6DAAgF;AAChF,qDAAwC;AAExC,SAAe,aAAa,CAAC,MAAuB;;QAClD,MAAM,CAAC,IAAI,CACT,GAAG,EACH;YACE,UAAU,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC;YACjC,MAAM,EAAE;gBACN,IAAI,EAAE,IAAA,qBAAI,EAAC,qBAAqB,CAAC;gBACjC,QAAQ,EAAE;oBACR,GAAG,EAAE,IAAA,qBAAI,EAAC,uBAAuB,CAAC;iBACnC;aACF;SACF,EACD,yCAAoB,CACrB,CAAC;QAEF,MAAM,CAAC,GAAG,CACR,GAAG,EACH;YACE,MAAM,EAAE;gBACN,QAAQ,EAAE;oBACR,GAAG,EAAE,IAAA,qBAAI,EAAC,wBAAwB,CAAC;iBACpC;aACF;SACF,EAED,uCAAkB,CACnB,CAAC;IACJ,CAAC;CAAA;AAED,kBAAe,aAAa,CAAC","sourcesContent":["import { FastifyInstance } from \"fastify\";\nimport { createProductHandler, getProductsHandler } from \"./product.controller\";\nimport { $ref } from \"./product.schema\";\n\nasync function productRoutes(server: FastifyInstance) {\n server.post(\n \"/\",\n {\n preHandler: [server.authenticate],\n schema: {\n body: $ref(\"createProductSchema\"),\n response: {\n 201: $ref(\"productResponseSchema\"),\n },\n },\n },\n createProductHandler\n );\n\n server.get(\n \"/\",\n {\n schema: {\n response: {\n 200: $ref(\"productsResponseSchema\"),\n },\n },\n },\n\n getProductsHandler\n );\n}\n\nexport default productRoutes;\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"9c18e800eee1bdea952b46ba9cff51c35f9e8a9e","contentHash":"21cc167db4a9bbcd6c0730e926a4e2dd2a450f37e7a99d1822b34ff430cb6e72"},"/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":0},"end":{"line":11,"column":62}},"13":{"start":{"line":12,"column":0},"end":{"line":12,"column":67}},"14":{"start":{"line":13,"column":26},"end":{"line":13,"column":54}},"15":{"start":{"line":15,"column":4},"end":{"line":18,"column":7}},"16":{"start":{"line":16,"column":24},"end":{"line":16,"column":144}},"17":{"start":{"line":17,"column":8},"end":{"line":17,"column":23}},"18":{"start":{"line":20,"column":0},"end":{"line":20,"column":52}},"19":{"start":{"line":22,"column":4},"end":{"line":25,"column":7}},"20":{"start":{"line":23,"column":25},"end":{"line":23,"column":67}},"21":{"start":{"line":24,"column":8},"end":{"line":24,"column":24}},"22":{"start":{"line":27,"column":0},"end":{"line":27,"column":48}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"createProductHandler","decl":{"start":{"line":14,"column":9},"end":{"line":14,"column":29}},"loc":{"start":{"line":14,"column":39},"end":{"line":19,"column":1}},"line":14},"8":{"name":"(anonymous_8)","decl":{"start":{"line":15,"column":43},"end":{"line":15,"column":44}},"loc":{"start":{"line":15,"column":56},"end":{"line":18,"column":5}},"line":15},"9":{"name":"getProductsHandler","decl":{"start":{"line":21,"column":9},"end":{"line":21,"column":27}},"loc":{"start":{"line":21,"column":30},"end":{"line":26,"column":1}},"line":21},"10":{"name":"(anonymous_10)","decl":{"start":{"line":22,"column":43},"end":{"line":22,"column":44}},"loc":{"start":{"line":22,"column":56},"end":{"line":25,"column":5}},"line":22}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":1,"13":1,"14":1,"15":0,"16":0,"17":0,"18":1,"19":0,"20":0,"21":0,"22":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"b":{"0":[1,1,1],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/product/product.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA,uDAA+D;AAE/D,SAAsB,oBAAoB,CACxC,OAEE;;QAEF,MAAM,OAAO,GAAG,MAAM,IAAA,+BAAa,kCAC9B,OAAO,CAAC,IAAI,KACf,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IACxB,CAAC;QAEH,OAAO,OAAO,CAAC;IACjB,CAAC;CAAA;AAXD,oDAWC;AAED,SAAsB,kBAAkB;;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAA,6BAAW,GAAE,CAAC;QAErC,OAAO,QAAQ,CAAC;IAClB,CAAC;CAAA;AAJD,gDAIC","sourcesContent":["import { FastifyReply, FastifyRequest } from \"fastify\";\nimport { CreateProductInput } from \"./product.schema\";\nimport { createProduct, getProducts } from \"./product.service\";\n\nexport async function createProductHandler(\n request: FastifyRequest<{\n Body: CreateProductInput;\n }>\n) {\n const product = await createProduct({\n ...request.body,\n ownerId: request.user.id,\n });\n\n return product;\n}\n\nexport async function getProductsHandler() {\n const products = await getProducts();\n\n return products;\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2805c57ec3f7a13889daa7828ab38193979150be","contentHash":"528b19fa72a46ede7c7c8633e6a86c55d4a77c0b6c3c48655a4229ccf4818ba4"},"/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts","statementMap":{"0":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"1":{"start":{"line":3,"column":28},"end":{"line":3,"column":110}},"2":{"start":{"line":3,"column":91},"end":{"line":3,"column":106}},"3":{"start":{"line":4,"column":4},"end":{"line":9,"column":7}},"4":{"start":{"line":5,"column":36},"end":{"line":5,"column":97}},"5":{"start":{"line":5,"column":42},"end":{"line":5,"column":70}},"6":{"start":{"line":5,"column":85},"end":{"line":5,"column":95}},"7":{"start":{"line":6,"column":35},"end":{"line":6,"column":100}},"8":{"start":{"line":6,"column":41},"end":{"line":6,"column":73}},"9":{"start":{"line":6,"column":88},"end":{"line":6,"column":98}},"10":{"start":{"line":7,"column":32},"end":{"line":7,"column":116}},"11":{"start":{"line":8,"column":8},"end":{"line":8,"column":78}},"12":{"start":{"line":11,"column":22},"end":{"line":13,"column":1}},"13":{"start":{"line":12,"column":4},"end":{"line":12,"column":62}},"14":{"start":{"line":14,"column":0},"end":{"line":14,"column":62}},"15":{"start":{"line":15,"column":0},"end":{"line":15,"column":53}},"16":{"start":{"line":16,"column":17},"end":{"line":16,"column":63}},"17":{"start":{"line":18,"column":4},"end":{"line":22,"column":7}},"18":{"start":{"line":19,"column":8},"end":{"line":21,"column":11}},"19":{"start":{"line":24,"column":0},"end":{"line":24,"column":38}},"20":{"start":{"line":26,"column":4},"end":{"line":41,"column":7}},"21":{"start":{"line":43,"column":0},"end":{"line":43,"column":34}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":2,"column":44},"end":{"line":2,"column":45}},"loc":{"start":{"line":2,"column":89},"end":{"line":10,"column":1}},"line":2},"1":{"name":"adopt","decl":{"start":{"line":3,"column":13},"end":{"line":3,"column":18}},"loc":{"start":{"line":3,"column":26},"end":{"line":3,"column":112}},"line":3},"2":{"name":"(anonymous_2)","decl":{"start":{"line":3,"column":70},"end":{"line":3,"column":71}},"loc":{"start":{"line":3,"column":89},"end":{"line":3,"column":108}},"line":3},"3":{"name":"(anonymous_3)","decl":{"start":{"line":4,"column":36},"end":{"line":4,"column":37}},"loc":{"start":{"line":4,"column":63},"end":{"line":9,"column":5}},"line":4},"4":{"name":"fulfilled","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":26}},"loc":{"start":{"line":5,"column":34},"end":{"line":5,"column":99}},"line":5},"5":{"name":"rejected","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":25}},"loc":{"start":{"line":6,"column":33},"end":{"line":6,"column":102}},"line":6},"6":{"name":"step","decl":{"start":{"line":7,"column":17},"end":{"line":7,"column":21}},"loc":{"start":{"line":7,"column":30},"end":{"line":7,"column":118}},"line":7},"7":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":56},"end":{"line":11,"column":57}},"loc":{"start":{"line":11,"column":71},"end":{"line":13,"column":1}},"line":11},"8":{"name":"createProduct","decl":{"start":{"line":17,"column":9},"end":{"line":17,"column":22}},"loc":{"start":{"line":17,"column":29},"end":{"line":23,"column":1}},"line":17},"9":{"name":"(anonymous_9)","decl":{"start":{"line":18,"column":43},"end":{"line":18,"column":44}},"loc":{"start":{"line":18,"column":56},"end":{"line":22,"column":5}},"line":18},"10":{"name":"getProducts","decl":{"start":{"line":25,"column":9},"end":{"line":25,"column":20}},"loc":{"start":{"line":25,"column":23},"end":{"line":42,"column":1}},"line":25}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":16},"end":{"line":10,"column":1}},"type":"binary-expr","locations":[{"start":{"line":2,"column":17},"end":{"line":2,"column":21}},{"start":{"line":2,"column":25},"end":{"line":2,"column":39}},{"start":{"line":2,"column":44},"end":{"line":10,"column":1}}],"line":2},"1":{"loc":{"start":{"line":3,"column":35},"end":{"line":3,"column":109}},"type":"cond-expr","locations":[{"start":{"line":3,"column":56},"end":{"line":3,"column":61}},{"start":{"line":3,"column":64},"end":{"line":3,"column":109}}],"line":3},"2":{"loc":{"start":{"line":4,"column":16},"end":{"line":4,"column":34}},"type":"binary-expr","locations":[{"start":{"line":4,"column":16},"end":{"line":4,"column":17}},{"start":{"line":4,"column":22},"end":{"line":4,"column":33}}],"line":4},"3":{"loc":{"start":{"line":7,"column":32},"end":{"line":7,"column":115}},"type":"cond-expr","locations":[{"start":{"line":7,"column":46},"end":{"line":7,"column":67}},{"start":{"line":7,"column":70},"end":{"line":7,"column":115}}],"line":7},"4":{"loc":{"start":{"line":8,"column":51},"end":{"line":8,"column":67}},"type":"binary-expr","locations":[{"start":{"line":8,"column":51},"end":{"line":8,"column":61}},{"start":{"line":8,"column":65},"end":{"line":8,"column":67}}],"line":8},"5":{"loc":{"start":{"line":11,"column":22},"end":{"line":13,"column":1}},"type":"binary-expr","locations":[{"start":{"line":11,"column":23},"end":{"line":11,"column":27}},{"start":{"line":11,"column":31},"end":{"line":11,"column":51}},{"start":{"line":11,"column":56},"end":{"line":13,"column":1}}],"line":11},"6":{"loc":{"start":{"line":12,"column":11},"end":{"line":12,"column":61}},"type":"cond-expr","locations":[{"start":{"line":12,"column":37},"end":{"line":12,"column":40}},{"start":{"line":12,"column":43},"end":{"line":12,"column":61}}],"line":12},"7":{"loc":{"start":{"line":12,"column":12},"end":{"line":12,"column":33}},"type":"binary-expr","locations":[{"start":{"line":12,"column":12},"end":{"line":12,"column":15}},{"start":{"line":12,"column":19},"end":{"line":12,"column":33}}],"line":12}},"s":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":1,"13":1,"14":1,"15":1,"16":1,"17":0,"18":0,"19":1,"20":0,"21":1},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":1,"8":0,"9":0,"10":0},"b":{"0":[1,1,1],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[1,1,1],"6":[1,0],"7":[1,1]},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/product/product.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,gEAAwC;AAGxC,SAAsB,aAAa,CACjC,IAA8C;;QAE9C,OAAO,gBAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YAC3B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;CAAA;AAND,sCAMC;AAED,SAAgB,WAAW;IACzB,OAAO,gBAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC7B,MAAM,EAAE;YACN,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI;YACX,EAAE,EAAE,IAAI;YACR,SAAS,EAAE,IAAI;YACf,SAAS,EAAE,IAAI;YACf,KAAK,EAAE;gBACL,MAAM,EAAE;oBACN,IAAI,EAAE,IAAI;oBACV,EAAE,EAAE,IAAI;iBACT;aACF;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAjBD,kCAiBC","sourcesContent":["import prisma from \"../../utils/prisma\";\nimport { CreateProductInput } from \"./product.schema\";\n\nexport async function createProduct(\n data: CreateProductInput & { ownerId: number }\n) {\n return prisma.product.create({\n data,\n });\n}\n\nexport function getProducts() {\n return prisma.product.findMany({\n select: {\n content: true,\n title: true,\n price: true,\n id: true,\n createdAt: true,\n updatedAt: true,\n owner: {\n select: {\n name: true,\n id: true,\n },\n },\n },\n });\n}\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"4d893c9a2b4373e742772417fd73f7ae76ad1dbf","contentHash":"ce38dd022b459ace479469409183785096b20f0168b9928abc13c194606d4e68"},"/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts":{"path":"/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":62}},"1":{"start":{"line":4,"column":0},"end":{"line":4,"column":47}},"2":{"start":{"line":5,"column":14},"end":{"line":5,"column":28}},"3":{"start":{"line":6,"column":22},"end":{"line":6,"column":44}},"4":{"start":{"line":7,"column":21},"end":{"line":11,"column":1}},"5":{"start":{"line":12,"column":25},"end":{"line":16,"column":1}},"6":{"start":{"line":17,"column":28},"end":{"line":17,"column":75}},"7":{"start":{"line":18,"column":30},"end":{"line":18,"column":110}},"8":{"start":{"line":19,"column":31},"end":{"line":19,"column":67}},"9":{"start":{"line":20,"column":0},"end":{"line":24,"column":64}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1},"f":{},"b":{},"inputSourceMap":{"version":3,"file":"/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts","sources":["/Users/tom/projects/fastify-prisma/src/modules/product/product.schema.ts"],"names":[],"mappings":";;;;AAAA,6BAAwB;AACxB,6CAA+C;AAE/C,MAAM,YAAY,GAAG;IACnB,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;IACjB,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;IACjB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC;AAEF,MAAM,gBAAgB,GAAG;IACvB,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE;IACd,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;IACrB,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;CACtB,CAAC;AAEF,MAAM,mBAAmB,GAAG,OAAC,CAAC,MAAM,mBAC/B,YAAY,EACf,CAAC;AAEH,MAAM,qBAAqB,GAAG,OAAC,CAAC,MAAM,iCACjC,YAAY,GACZ,gBAAgB,EACnB,CAAC;AAEH,MAAM,sBAAsB,GAAG,OAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;AAIjD,KAAoC,IAAA,8BAAgB,EAAC;IAChE,mBAAmB;IACnB,qBAAqB;IACrB,sBAAsB;CACvB,CAAC,EAJsB,sBAAc,eAAE,YAAI,WAIzC","sourcesContent":["import { z } from \"zod\";\nimport { buildJsonSchemas } from \"fastify-zod\";\n\nconst productInput = {\n title: z.string(),\n price: z.number(),\n content: z.string().optional(),\n};\n\nconst productGenerated = {\n id: z.number(),\n createdAt: z.string(),\n updatedAt: z.string(),\n};\n\nconst createProductSchema = z.object({\n ...productInput,\n});\n\nconst productResponseSchema = z.object({\n ...productInput,\n ...productGenerated,\n});\n\nconst productsResponseSchema = z.array(productResponseSchema);\n\nexport type CreateProductInput = z.infer;\n\nexport const { schemas: productSchemas, $ref } = buildJsonSchemas({\n createProductSchema,\n productResponseSchema,\n productsResponseSchema,\n});\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"c5c6a36746e42423277a378c4a40a4007838c18f","contentHash":"2fb46a38bda61d7da225c158a3c31ab965138f872b82c5f3e2af88f580d92c5e"}} --------------------------------------------------------------------------------