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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@uon/server

v0.4.0

Published

An HTTP server application framework with Let's Encrypt integration.

Downloads

12

Readme

UON SERVER

A web server written in Typescript with Let's Encrypt built-in. This package is based on the @uon/core application architecture.

Please note that there are many unfinished features, use at your own risk.

Usage

    npm i @uon/server

Introduction

Http Module

The http module is responsible for handling http requests and spawning an HttpContext.

App-wide Providers vs Request-Scoped Providers

Providers declared in @Module() decorator are availble through DI across the application instance. Request-scoped providers are declared with HttpModule.WithConfig() or with HTTP_CONFIG

Routing

Http routing is done with @uon/router and the http sub-module provides 2 routers: HTTP_ROUTER and HTTP_REDIRECT_ROUTER.

To declare routes you can do the following:

First declare a controller with HttpRoute decorators on methods:


import { Controller } from '@uon/router';

@Controller()
export class MyAppController {

    // ctor with dependency injection 
    constructor(private response: HttpResponse) {}

    @HttpRoute({
        method: 'GET',
        path: '/say-hello'
    })
    myStaticPathRoute() {
        this.response.send('Hello World!');
    }

}

Second, declare a list of routes that will be used by the HttpServer:

const routes: Routes = [
    {
        path:'/my-base-path',
        controller: MyAppController
    }
];

Finally, import RouterModule like so, to bind routes to the correct router:

@Module({
    imports: [
        RouterModule.For(HTTP_ROUTER, routes)
    ]
})
export class MyModule {}

HttpTransform

HttpTransform is an interface that classes can implement to transform an HttpResponse. @uon/server provides a few transforms including:

  • HttpCache
  • HttpCookies
  • HttpEncoding
  • HttpRange
  • HttpSecurity

All of these are in the default provider list and can be used by simply adding the instance (obtained by DI) to the response object.

    constructor(
        private response: HttpResponse, 
        private cookies: HttpCookies
    ) {

        this.cookies.setCookie('mycookie', 'mycookievalue');

        // use cookies
        this.response.use(this.cookies);
    }
    

HttpContext

An HttpContext is responsible for matching the request pathname to one or more controllers. Each request to the server spawns an isolated context where only what is needed is instanciated.

You will never have to use HttpContext directly, instead use HttpResponse and HttpRequest

Let's Encrypt Module

The LetsEncryptModule is responsible for obtaining certificates from the authority. This module works along with the HttpModule in the following way:

  • When the application starts, LetsEncryptModule registers itself as the HTTP_SSL_PROVIDER
  • The HttpServer looks up the HTTP_SSL_PROVIDER.
  • If it is found, HttpServer requests the certificates. A plain http server start listening for requests at this point.
  • If no certificates can be found using the provided storage adapter, the service will request them from the authority.
  • An http-01 challenge is prepared, sent to LE and waits for the authority to request the keyauth from this here server (in plain http)
  • The certificates are signed and downloaded from LE
  • Finally, an https server is created and configured with SNICallbacks.

Usage

To get Let's Encrypt certificates for your server, you simply need to add the module with a config to your application's main module imports :


import {
    LetsEncryptModule, 
    LetsEncryptLocalStorageAdapter
} from '@uon/server';

@Module({
    imports: [
        ...
        LetsEncryptModule.WithConfig({

            // A storage adapter is required to store accounts, 
            // certificates and challenges
            storageAdapter: new LetsEncryptLocalStorageAdapter({ 
                 baseDir: path.join(__dirname, '/certs') 
            }),

            // the account to use, must be an email address
            account: "[email protected]",

            // a list of domains
            domains: ["example.com", "www.example.com"],

            // optional temporary folder, if not provided it 
            // defaults to os.tmpdir()
            tempDir: path.join(__dirname, '/temp'),

            // either "staging" or "production"
            // make sure everything works before switching to "production"
            // as rate-limiting will get you banned in no time
            environment: "staging"
         })
         ...
    ]
   
})
export class MyAppModule() {}

Challenge types

Only the http-01 challenge has been implemented. There are no immediate plans to implement other challenge types.

Storage adapters

A generic storage adapter is provided (LetsEncryptFsStorageAdapter) using any FsAdapter as backend. Implementing a storage adapter for MongoDB or Redis can be done by implementing the interface LetsEncryptStorageAdapter.

Websocket Module

An simple implementation of Websocket.

Upgrading connections

Connection upgrades are done by using an HttpRoute with the method "UPGRADE". An HttpUpgradeContext is made available as a provider when an upgrade request comes in.

Example

import { HttpController, HttpRoute, HttpUpgradeContext, WebSocket } from '@uon/server';

@Controller()
export class MyController {


    constructor(private upgradeContext: HttpUpgradeContext) {

    }

    @HttpRoute({
        method: 'UPGRADE', // special method for upgrade requests
        path: '/ws-upgrade-path'
    })
    doUpgrade() {

        // check auth or any other condition for upgrade
        return auth.getAuth(...)
            .then((res) => {

                if(!res) {
                    // reject the upgrade
                    return this.upgradeContext.abort(403, 'You shall not pass.')
                }

                // continue with the upgrade
                return this.upgradeContext.accept(WebSocket)
                    .then((ws) => {

                        ws.on('message', (data) => {
                            console.log('received message', data);
                        });

                        ws.on('close', (code) => {
                            console.log('connection closed', code);
                        });

                        ws.send('From server, with love.');

                    });
            });
    }
}

File System Module

The FsModule takes a list of user-implementable file system adapters.

A local file system adapter is provided (LocalFsAdapter) for access to a folder.

We implemented a S3 adapter in @uon/server-aws.

Cluster Module

The cluster module is responsible for the application's lifecycle. By default, clustering is not enabled and run's the app on a single thread.

To enable clustering, you must provide a config in your providers (or imports with ClusterModule.WithConfig(...))

import {
    ClusterModule, 
    FileLockAdapter
} from '@uon/server';

@Module({
    imports: [
        ...

        ClusterModule.WithConfig({
            enabled: true,
            concurrency: 8,
            lockAdapter: new FileLockAdapter()
        })
        ...
    ]
})
export class MyMainModule {}

More info coming soon.

Lifecycle hooks

You can hook into the app's lifecycle with these multi-providers :

  • CLUSTER_MASTER_INIT ; Execute task on launch on the master process only
  • CLUSTER_WORKER_INIT ; Execute task on launch on the worker processes (on master if clustering is disabled)
  • CLUSTER_MASTER_EXIT ; Execute task when the application exits on master process
  • CLUSTER_WORKER_EXIT ; Execute task when the application exits on worker process (on master if clustering is disabled)

Logging

@uon/server provides utilities for logging. You can implement your own logger by implementing the interface LogAdapter.

Contributions

You are welcome to contribute by filling issues or submitting pull requests. Much love.

Future Development

  • Reverse-proxy module