npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@vigilio/next-api

v0.0.5

Published

next api viglio

Readme

@Vigilio/next-api

A simple library for use next api (no app pages - next js).

npm install @vigilio/next-api

Getting Started

// /src/pages/api/[[...params]].ts

import { createHandler, Get } from "@vigilio/next-api";

class UsersController {
    @Get()
    public async users() {
        return await DB.findUsers();
    }
}

export default createHandler([UsersController]);
  • Compiler Options - tsconfig.json
"experimentalDecorators": true,
"emitDecoratorMetadata": true

Route

npm install path-to-regexp
// /src/pages/api/[[...params]].ts

import { createHandler, Get, Param, Post } from "@vigilio/next-api";

class UsersController {
    @Get()
    index() {
        return DB.findAllUsers();
    }

    @Get("/:id")
    public show(@Param("id") id: string) {
        return DB.findUserById(id);
    }

    @HttpCode(201)
    @Post("/")
    store(@Body() body: { name: string; lastname: string }) {
        return DB.create(body);
    }

    @HttpCode(201)
    @Put("/")
    update(
        @Param("id") id: string,
        @Body() body: { name: string; lastname: string }
    ) {
        return DB.updateById(id, body);
    }

    @Delete("/")
    destroy(@Param("id") id: string) {
        return DB.destroy(id);
    }
}

export default createHandler([UsersController, ...morecontrollers], true); //true you dont need create directories because will be a dynamic automatically params. false will need directories and files to read params @default false

Validators and Pipes

Using @vigilio/valibot to validate

npm install @vigilio/valibot

Docs @vigilio/valibot https://www.npmjs.com/package/@vigilio/valibot

// src/users/schema.ts - you can custom your file name
import {
    array,
    Input,
    literal,
    number,
    objectAsync,
    string,
    union,
    maxLength,
    minLength,
    boolean,
    email,
    maxValue,
    minValue,
    object,
    nullable,
} from "@vigilio/valibot";

export const usersSchema = objectAsync({
    id: number(),
    name: string([minLength(3), maxLength(10)]),
    email: string([email()]),
    age: number([minValue(18), maxValue(120)]),
    role: union([literal("admin"), literal("client")]), // enum : admin|client
    enabled: boolean(),
    hobbies: array(string()),
    address: nullable(object({ zip: string(), code: string() })), // can be a nullable
});
// you can use omit,merge,pick,etc from valibot
export const usersStoreDto = omitAsync(usersSchema, ["id"]);
export type UsersStoreDto = Input<typeof usersStoreDto>;

export const usersUpdateDto = omitAsync(usersSchema, ["id"]);
export type UsersUpdateDto = Input<typeof usersUpdateDto>;
export class UsersController {
    @HttpCode(201)
    @Validator(usersStoreDto) //body validation
    @Post("/users")
    async store(@Body() body: UsersStoreDto) {}

    @HttpCode(201)
    @Validator(usersUpdateDto)
    @Pipe(objectAsync({ id: string() })) //param validation
    @Put("/users/:id")
    async update(@Body() body: UsersUpdateDto, @Param("id") id: string) {}
}

Injectable and Handle Errors

import { BadRequestException, NotFoundException } from "@vigilio/next-api";

export class UsersService {
    async index() {
        const data = await Users.findAll();
        return { success: true, data };
    }

    async show(id: string) {
        const user = await Users.findByPk(id);
        if (!user) {
            // handle error
            throw new NotFoundException(`No se encontró un usuario ${id}`);
        }
        return { success: true, user };
    }

    async store(body: UsersStoreDto) {
        const user = await Users.create(body);
        return { success: true, user };
    }

    async update(id: string, body: UsersUpdateDto) {
        const { user } = await this.show(id);
        await user.update(body);
        return { success: true, user };
    }
    async destroy(id: string) {
        const { user } = await this.show(id);
        return { success: true, message: "remvoe succelly" };
    }
}

@Injectable()
export class UsersController {
    constructor(private readonly usersService: UsersService) {}
	@Get("/users")
	async index() {
		const result = await this.usersService.index(); //you can use
		return result;
	}
    ....
}

| Exception | Status Code | Default Message | | ------------------------------ | ----------- | ----------------------- | | BadRequestException | 400 | 'Bad Request' | | UnauthorizedException | 401 | 'Unauthorized' | | ForbiddenException | 403 | 'Forbidden' | | NotFoundException | 404 | 'Not Found' | | ConflictException | 409 | 'Conflict' | | PayloadTooLargeException | 413 | 'Payload Too Large' | | UnprocessableEntityException | 422 | 'Unprocessable Entity' | | InternalServerErrorException | 500 | 'Internal Server Error' |

Custom Middleware

import {
    createMiddlewareDecorator,
    UnauthorizedException,
    UnauthorizedException,
} from "@vigilio/next-api";

const JwtAuthGuard = createMiddlewareDecorator(
    (req: NextApiRequest, res: NextApiResponse, next: NextFunction) => {
        if (!validateJwt(req)) {
            throw new UnauthorizedException();
            // or
            return next(new UnauthorizedException());
        }

        next();
    }
);

class SecureHandler {
    @Get()
    @JwtAuthGuard() //use middleware
    public securedData(): string {
        return "Secret data";
    }
}

Custom Decorator

import { createParamDecorator } from "@vigilio/next-api";

export const UserAgent = createParamDecorator<string | undefined>(
    (req) => req.headers["user-agent"]
);
class CommentHandler {
    @Get()
    public comments(@UserAgent() userAgent?: string) {
        return `Someone requested the comments via "${
            userAgent ?? "Unknown browser"
        }"`;
    }
}
npm install formidable
import { NextApiRequest, NextApiResponse } from "next";
import {
    createMiddlewareDecorator,
    NextFunction,
} from "./middleware.decorators";
import formidable, { type File } from "formidable";

export const Upload = () =>
    createMiddlewareDecorator(
        async (
            req: NextApiRequest,
            res: NextApiResponse,
            next: NextFunction
        ) => {
            const form = formidable();

            try {
                const [fields, files] = await form.parse(req);
                const archivos = files.file;
                req.files = archivos;
                if (fields.name) {
                    req.filesName = fields.name[0];
                }
                next();
            } catch (error) {
                return res.status(500).json({
                    success: false,
                    message: "Error ",
                });
            }
        }
    )(); //()

export class UploadsController {
    @Upload()
    @Post("/:entity/:property")
    async store(@Body() body: { files: string; filesName: string }) {
        console.log({ body });
        return result;
    }
}
// src/pages/uploads/[[...params]].ts
import { createHandler } from "@vigilio/next-api";
// next js config to upload files
export const config = {
    api: {
        bodyParser: false,
    },
};

export default createHandler([UploadsController]);