
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Pee ‧ ee ‧ lawn ‧ ee - Hawaiian; to go up to the heavens/sky.
A framework for building cloud-based Node.js TypeScript back-end Web services.
⚠️ UNDER DEVELOPMENT: NOT PRODUCTION READY ⚠️
If you have any questions, development ideas, or you'd like to contribute, please contact me or create an issue on Github.
Add Piilani to your project.
npm i piilani
yarn add piilani
To initialize your project directory run the following Piilani command:
./node_modules/piilani/bin/cli init
This will install all required dependencies and create a config
directory with config files for each supported environment.
There are 3 runtime environments and the PIILANI_ENV environment variable to
specify which one the app is currently running in:
+-------------------+---------------+
| Environment | PIILANI_ENV |
+-------------------+---------------+
| development | dev |
+-------------------+---------------+
| non-production | non-prod |
+-------------------+---------------+
| production | prod |
+-------------------+---------------+
After initializing the project (see Getting Started), you'll have 4
configuration files in your config directory. The config.json file is the
default. The dev.config.json, non-prod.config.json, and prod.config.json
files are for overriding the default configuration in the respective runtime
environments (see Environment).
The following values must be set in your tsconfig.json.
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6"
},
}
At the entry point for the service, reflect-metadata must be imported.
This is required for decorator support. In Piilani, the entry point is
conventionally startup.ts. More on that in the Dependency Injection
section.
import 'reflect-metadata';
Dependency injection is handled by tsyringe. The recommended way of
working with the library is to create a startup.ts file at the root
of your project's source code. In this file, we can include the
required reflect-metadata package, and manage the Dependency
Injection container.
The startup.ts MUST be included before any application code.
import 'reflect-metadata';
import { container } from 'tsyringe';
export const DependencyInjection = container;
container.register(/*token, value/class*/)
For more on dependency injection, see the tsyringe
documentation.
If your project grows very large, you can split the file and include
the child files in the parent startup.ts.
TODO: This could be scripted. Options should exist for creating a startup.ts in a new or existing project.
By default, the HTTP server will run unsecured. To run the server secured (over HTTPS), add the cert and key files to the config file(s).
The files are paths relative to the project's root directory.
{
"listenPort": 443,
"ssl": {
"cert": "ssl/ssl.cert",
"key": "ssl/ssl.key"
}
}
The app can be configured to use one or many databases. Currently, only
PostgreSQL and Mongodb are officially supported. You can still use other
databases, but certain convenience functions (like the
getConnectionString method of the Config class) will be unusable.
The base of a RESTful Web service is the RestController.
import { injectable } from 'piilani/context';
import { RestController } from 'piilani/controllers/http';
@injectable()
class ListController extends RestController {
// Class definition here...
}
This controller is now primed to handle incoming HTTP requests. Without
specifying a basePath, the controller will handle routes with paths
starting from the root /. Alternatively, the basePath can be set in
the constructor.
import { inject, injectable } from 'piilani/context';
@injectable()
class ListController extends RestController {
private gateway: IListsGateway;
public constructor(@inject('IListsGateway')gateway: IListsGateway) {
super()
this.gateway = gateway;
this.basePath = '/lists';
}
}
Now all route paths handled by this controller will begin with /lists.
To handle HTTP requests, use the get, post, put, and delete
decorators.
The following method, annotated with the @get() decorator, will
handle get requests to the controller's base path (/ by default, see
the RestController section for details on how to set base path).
import { HttpResponse, NoContent, Ok, ServerError } from 'piilani/controllers/http/response';
import { del, get, post, put } from 'piilani/decorators/restful';
@injectable()
class ListController extends RestController {
// code omitted.
@get()
public async getAllLists(): Promise<HttpResponse<List[]>> {
const res = await this.gateway.findAsync();
if (res.data) {
return Ok(res.data);
}
if (res.class === 2) {
return NoContent();
}
return ServerError();
}
}
If you want the annotated methods to handle more specific routes, add the path (relative to the RestController's basePath) to the decorator's invocation.
@injectable()
export class ListsController extends RestController {
// code omitted.
@get('/index')
public async getListIndex(): Promise<HttpResponse<ListIndex[]>> {
const res = await this.gateway.findIndexAsync();
if (res.data) {
return Ok(res.data);
}
if (res.class === 2) {
return NoContent();
}
return ServerError();
}
}
TODO: Document the usage of @fromPath decorator.
import { fromQuery, get } from 'piilani/decorators/restful';
@injectable()
export class ListsController extends RestController {
// code omitted.
@get()
public async getListById(@fromQuery('id') id: string): Promise<HttpResponse<List>> {
const res = await this.gateway.findAsync({ id })
if (res.data) {
return Ok(res.data[0]);
}
if (res.class === 2) {
return NoContent();
}
return BadRequest();
}
}
import { fromBody, get } from 'piilani/decorators/restful';
@injectable()
export class ListsController extends RestController {
// code omitted.
@post()
public async addList(@fromBody()list: Partial<Omit<List, 'id'>>): Promise<HttpResponse> {
const res = await this.gateway.insertAsync(new List(list));
if (res.class === 1) {
return Created();
}
if (res.class === 2) {
return BadRequest();
}
return ServerError();
}
}
TODO: Document the Authentication configuration.
// startup.ts
import { Authentication } from 'piilani/services/auth/Authentication';
DependencyInjection.register(Gateways.Users, UsersMongoGateway);
Authentication.configure({
// Minutes until keys expire.
exp: 60,
gateway: DependencyInjection.resolve<IUsersGateway>(Gateways.Users),
privateKey: '<private-key or secret>',
});
To require users to be authenticated to access routes, add the
@authenticated decorated to the Route's method.
This will require uses to pass a JWT Bearer token
along with the request in the HTTP Authorization header.
import { authenticated, post, fromBody } from 'piilani/decorators/restful';
class ListsController extends RestController {
// --- code omitted -- //
@authenticated()
@post()
public async addList(@fromBody()list: List): Promise<HttpResponse> {
const res = await this.gateway.insert(new List(list));
if (res.class === 1) {
return Created();
}
if (res.class === 2) {
return BadRequest();
}
return ServerError();
}
}
FAQs
Just another Web application framework.
The npm package piilani receives a total of 55 weekly downloads. As such, piilani popularity was classified as not popular.
We found that piilani demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.