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

@ballena/server

v1.0.20

Published

Ballena Container System

Downloads

52

Readme

@ballena/server

Ballena es una plataforma diseñada para equipos de desarrollo que generan APIs y Aplicaciones Web basados en Node JS, usando Express JS para generar API REST.

Introducción


La principal característica de Ballena es aislar los códigos fuente de los programadores para unificar dependencias y facilitar el despliegue continuo de servidores sin tener que detenerlos o exponer sus credenciales.

Filosofía

Ballena sigue la filosofía de los DevOps y Kubernetes creando un ambiente de desarrollo continuo el cuál se pretende no sea detenido ni reiniciado para la integración de nuevos contenedores y módulos (paquetes y librerías). Esto permite que el desarrollo no se detenga operativamente y el proceso de despliegue e implementación de código sea más rápido y sencillo.

Ballena busca crear equipos de desarrollo ágiles, que puedan montar servidores locales y productivos de manera uniforme, para poder crear desarrollos estables y productivos mediante trabajo colaborativo automatizado.

Ballena consiste en los siguientes conceptos:

  1. Contenedor - Es el conjunto de códigos que definen las APIs y las visas y pueden ser compartidos.
  2. Paquetes - Son los nombres de los paquetes de Node JS que pueden ser instalados mediante npm.
  3. Librerías - Son módulos adaptados por los programadores, sobre los paquetes para poder simplificarlos.
  4. Accesibilidad - Puede ser instalado mediante npm install @ballena/server.
  5. Integración continua - Puede importar contenedores, paquetes y librerías al servidor sin necesidad de detenerlo, vía API o desde el panel de administración.
  6. Distribución continua - Permite a los equipos de desarrollo compartirse contendores y librerías e integrarlos en sus ambientes locales o productivos.

Arquitectura

La arquitectura consiste básicamente en exponer las rutas de las API y las vistas a través del registro clásico de rutas de express. Adicionalmente, puedes configurar un panel para administrar los módulos que serán desarrollados continuamente por el equipo, para distribuirlos, activarlos o desactivarlos.

Tutorial


En este tutorial se mostrará el uso de @ballena/server.

1. Configurar el proyecto (ambiente)

Un proyecto para @ballena/server equivale a un ambiente de desarrollo (local o productivo).

  • Crea la carpeta my-ambient o del nombre que gustes llamarle a tu proyecto, aquí usuaremos ambient.
mkdir ambient
cd ambient

Los proyectos de servidores suelen ser un archivo de node que se ejecutan.

  • Crea el archivo de entrada index.js o como acostumbres llamarle y usa el servidor de ballena (es en realidad un servidor de express tradicional).

ambient/index.js

const ballena = require("@ballena/server");

const server = ballena.httpServer();

server.start();
  • Ejecuta el servidor con node index.js o node . (pulsa ctrl + c para detenerlo).
node .

Se prenderá un servidor en http://localhost:4000/ o puedes configurar el puerto específico con server.start(5000) (dónde ahora el puerto es 5000 y la url es http://localhost:4000/).

2. Crear un contenedor

Los contenedores se dividen en APIs y Vistas. Cuándo se crean o actualizan contenedores no hay necesidad de reiniciar el servidor, a esto se le llama Integración Containua ya que podemos integrar y actualizar contenedores sólo reemplazando los archivos de código.

¡Advertencia! lea cuidadósamente la sección correspondiente al Modo Productivo: Seguridad y Optimización.

Una API es un archivo de javascript que devuelve una respuesta JSON. Estas son llamadas de la forma http://localhost:4000/<container-name>/api/<api-name>, dónde <container-name> es el nombre del contenedor y <api-name> es el nombre del api.

  • Crea el contendor llamado todo. Para esto crea las carpetas todo, todo/api y todo/view desde la carpeta principal. Dentro de la carpeta todo/api coloca un archivo llamado index.js.

ambient/todo/api/index.js

return "Hello TODO api";

Ve a la ruta http://localhost:4000/todo/api. Deberías obtener una respuesta similar a la siguiente.

{
    "ballena": "v1.0",
    "container": "todo",
    "api": "index",
    "exists": true,
    "error": null,
    "result": "Hello TODO api",
    "logs": []
}
  • Crea una vista colocando un archivo index.html dentro de la carpeta todo/view, todos los códigos puestos aquí serán públicos, incluyendo las subcarpetas. Esto funciona al estilo public_html o www_root de otros tipos de servidores. Aquí se propone una estructura view/index.html, view/cdn/css/style.css, view/cdn/js/app.js, etc.

ambient/todo/view/index.html

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>TODO App</title>

</head>

<body>

    <h1>Hello TODO view</h1>

</body>

</html>

Ve a la ruta http://localhost:4000/todo. Deberías obtener una respuesta similar a la siguiente.

Hello TODO view

Ahora ya está configurado tu primer contenedor, agrega funcionalidad extra para ver el potencial de @ballena/server.

3. TO-DO App

Ahora configuraremos un ejemplo real para retener cosas por hacer en nuestro servidor.

ambient/todo/api/add.js

const title = input("title");

if (!title) throw new Error("Invalid TODO title");

container.todos = container.todos || [];

const todo = {
    id: container.todos.length + 1,
    title,
    checked: false,
    createAt: new Date()
};

container.todos.push(todo);

return todo;

ambient/todo/api/check.js

const id = input("id");

container.todos = container.todos || [];

const todo = container.todos.find(todo => todo.id === id);

if (!todo) throw new Error(`Invalid TODO with id ${id}`);

todo.checked = !todo.checked;

return todo;

ambient/todo/api/delete.js

const id = input("id");

container.todos = container.todos || [];

const todo = container.todos.find(todo => todo.id === id);

if (!todo) throw new Error(`Invalid TODO with id ${id}`);

container.todos = container.todos.filter(todo => todo.id !== id);

return todo;

ambient/todo/api/all.js

return container.todos || [];
<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Ballena - TODO App</title>

    <!-- Tailwind CSS -->
    <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">

    <!-- Fontawesome CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css">

</head>

<body style="opacity: 0; transition: opacity 1s;">

    <div class="p-16">
        <div class="flex items-center">
            <div class="px-2">
                <input @keydown="event.key !== 'Enter' || addTodo()" id="todoTitle" class="border-b pb-1 px-2"
                    placeholder="Write something to-do...">
            </div>
            <div>
                <button @click="addTodo()"
                    class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">add</button>
            </div>
        </div>
        <div class="p-4">
            <div :if="!todos || todos.length === 0">
                <span class="text-gray-500 italic">There are not todos</span>
            </div>
            <ul>
                <li :for="todos" :each="todo">
                    <div class="flex items-center">
                        <div class="px-2">
                            <input @change="checkTodo(todo)" type="checkbox" $checked="todo.checked">
                        </div>
                        <div class="text-gray-600">
                            <span $class="todo.checked ? 'line-through' : ''" $text="todo.title">TODO example</span>
                        </div>
                        <div class="px-2">
                            <span @click="removeTodo(todo)" class="text-red-500 hover:text-red-700 cursor-pointer">
                                <i class="fas fa-trash"></i>
                            </span>
                        </div>
                    </div>
                </li>
            </ul>
        </div>
    </div>

    <!-- Sweet Alert 2 -->
    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@9"></script>

    <!-- Zen -->
    <script src="https://badillosoft.github.io/zen/zen.js"></script>

    <script>
        handle("addTodo", async () => {
            const context = await getContext();

            const { error, result } = await post("/todo/api/add", {
                title: select("#todoTitle").value
            });

            if (error) {
                await Swal.fire("Error", error, "error");
                return;
            }

            await setContext({
                todos: [
                    ...context.todos,
                    result
                ]
            });

            select("#todoTitle").select();
        });

        handle("checkTodo", async todo => {
            const context = await getContext();

            const { error, result } = await post("/todo/api/check", {
                id: todo.id
            });

            if (error) {
                await Swal.fire("Error", error, "error");
                return;
            }

            await setContext({
                todos: context.todos.map(_todo => {
                    if (_todo.id === result.id) {
                        return result;
                    }
                    return _todo;
                })
            });
        });

        handle("removeTodo", async todo => {
            const context = await getContext();

            const { error, result } = await post("/todo/api/delete", {
                id: todo.id
            });

            if (error) {
                await Swal.fire("Error", error, "error");
                return;
            }

            await setContext({
                todos: context.todos.filter(_todo => {
                    return _todo.id !== result.id;
                })
            });
        });

        (async () => {

            await setContext({
                todos: []
            });

            const { error, result } = await post("/todo/api/all");

            document.body.style.opacity = 1;

            if (error) {
                await Swal.fire("Error", error, "error");
                return;
            }

            await setContext({
                todos: result
            });
        })();
    </script>

</body>

</html>

Puedes consultar el proyecto completo en https://github.com/badillosoft/ballena-todo.