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 🙏

© 2026 – Pkg Stats / Ryan Hefner

samanbayaka

v0.0.29

Published

Moleculer Gateway service with kafka transporter

Readme

samanbayaka

This project is a modular, production-ready microservices framework built with Moleculer and Moleculer-Web latest, using NATS as a high-performance messaging transporter and AJV for robust schema validation. It provides a scalable foundation for developing distributed Node.js applications, emphasizing fault tolerance, clean architecture, and efficient service communication. The system is designed to support flexible orchestration of services while maintaining strong validation and reliability across components.

NPM version License

Features

  • Moleculer-based microservices architecture
  • NATS transporter for high-performance messaging
  • Redpanda transporter for persistent,robust and scalability.
  • In memory L1 cache and Redis cache for L2
  • Schema validation using AJV
  • Dynamic service loading (Gateway / Feature / Demo)
  • Graceful shutdown handling (SIGINT, SIGTERM)
  • Centralized error handling middleware
  • REPL support for debugging
  • Config-driven initialization
  • Metrics and Log shipping for Grafana

Installation

pnpm install samanbayaka

Once the package is installed, you can import the library using import or require approach:

import sbk from "samanbayaka"

Prerequisites

It is assumed that NATS, Redpanda, Redis, and Etcd are installed and properly configured. All services should be discoverable through the /etc/hosts file.

Minimum required Node.js version: >= 22.x.x

node -v
nvm use 22

Additionally, OpenObserve is used to view logs and telemetry.

Environment variables

To configure all required environment variables, create a Bash file:

source /etc/profile.d/sbk.sh

Paste this:

## Credential for reading configurations from the Etcd server, the default port is 2379.
export SBK_CONFIG_CRED=<yout_user>:<your_pass>:<your_port>

## Configurations files path
export SBK_CONFIG_PATH=/usr/local/etc/<your_folder>

## Web server port 8760-8769
export SBK_PORT=8765

## Log level allowed values are fatal | error | warn | info | debug | trace
export SBK_LOG_LEVEL=info

## Maximum allowed TTL for the memoryLRU (L1) cache; the value is capped at 600 seconds.
export MAX_L1_TTL=120

## Maximum allowed TTL for the redis (L2) cache; the value is capped at 86400 seconds.
export MAX_L2_TTL=600

## Enabling telemetry middleware – Set the value to true; the default is false.
export SBK_TELEMETRY_ENABLE=false

Set environment variables in the current Bash session.

source /etc/profile.d/sbk.sh

Optionally, you may verify the set environment variables.

echo $SBK_PORT

Configuration files

Create a directory to store the configuration files, then copy all configuration files from the current project path into this directory and update them as needed. Before copying, ensure that your current working directory is the project directory.

pwd
sudo mkdir -p /usr/local/etc/<your_folder>
sudo cp config/*.*  /usr/local/etc/<your_folder>

Log files

For production, it is recommended to create a new directory named "samanbayaka" under /var/log to store logs.

sudo mkdir -p /var/log/samanbayaka
sudo chown -R $USER:$(id -gn) /var/log/samanbayaka
sudo chmod 755 /var/log/samanbayaka

Empty your log files if they become very large, as follows:

truncate -s 0 /var/log/samanbayaka/sbk-*.log

Setup logrotate (optional)

Create config file:

sudo nano /etc/logrotate.d/sbk

Paste this:

/var/log/samanbayaka/sbk-*.log {
  daily
  rotate 14
  compress
  delaycompress
  missingok
  notifempty
  copytruncate
  create 0640 node node
}

Documentations

Errors

sbk.Errors exposes the Moleculer Errors object.

getConfig

sbk.getConfig is a function that returns a configuration object from a specified file name.

The file is loaded from the configuration directory defined by the environment variable.

loadDemo

sbk.loadDemo is an asynchronous function that creates a demo service to help understand the project.

registerSystemAPI

sbk.registerSystemAPI is an asynchronous function that creates a gateway service to expose REST APIs for system management.

registerEdgeAPI

sbk.registerEdgeAPI is an asynchronous function that creates a gateway service to expose REST APIs.

registerServices

sbk.registerServices is an asynchronous function that creates a feature service.

Function Signature
sbk.registerServices(schema)
Parameter
  • schema - An object that follows the Moleculer service schema structure.

Example:

{
    name: "math",
    actions: {
        add(ctx) {
            return Number(ctx.params.a) + Number(ctx.params.b);
        },

        sub(ctx) {
            return Number(ctx.params.a) - Number(ctx.params.b);
        }
    }
}

registerBridgeServices

sbk.registerBridgeServices is a function used to initialize and manage message brokers such as Kafka, MQTT, and RabbitMQ.

Function Signature
sbk.registerBridgeServices(
  type,
  brokerOpts = {},
  callback = () => {}
)
Parameters
  • type (string) - Specifies the broker type to initialize. Supported values:

    • "kafka"
    • "mqtt"
    • "amqp"

Example:

"kafka"
  • brokerOpts (object) - Configuration object used to initialize the broker client, producer, and consumer. Example structure:
{
  name: <your_service_name>
  client: {},
  producer: {},
  consumer: {
    groupId: "all",
    interMessageDelayMs: 10,
  },
  logLevel: "INFO",
  gzip: true,
  msgPack: true,
  rest: false,
}

Configuration Options

| Property | Type | Description | |---|---|---| | name | string | Only lowercase letters (a–z), digits (0–9), and hyphens (-) are allowed. | | client | object | Broker client configuration | | producer | object | Producer configuration | | consumer | object | Consumer configuration | | consumer.groupId | string | Consumer group identifier is mandatory for the consumer | | consumer.interMessageDelayMs | number | Optional delay between messages in milliseconds | | logLevel | string | Logging level (NOTHING, ERROR, WARN, INFO, DEBUG), default NOTHING | | gzip | boolean | Enables message compression; only GZIP is supported, default true | | msgPack | boolean | Enables MessagePack serialization, default true | | rest | boolean | Enables REST end point, default false |

  • callback (function) - Callback function executed when a message/event is received.

Arguments

| Argument | Description | |---|---| | ctx | Broker context | | payload | Incoming message payload |

Example:

(ctx, payload) => {
  ctx.broker.logger.debug(payload)
}

Usage

Create gateway service

The Gateway is a critical service that exposes all endpoints as REST APIs. At least one Gateway service must be running to make the REST APIs accessible.

mkdir gateway
cd gateway
pnpm init
pnpm install samanbayaka
touch index.mjs

Open index.mjs and paste the following:

import sbk from "samanbayaka"
await sbk.registerEdgeAPI()

Create feature services

mkdir <your_service_name>
cd <your_service_name>
pnpm init
pnpm install samanbayaka
touch index.mjs

A feature service, such as hello, can be created as follows:

mkdir hello
cd hello
pnpm init
pnpm install samanbayaka
touch index.mjs

Open index.mjs and paste the following:

import sbk from "samanbayaka"
await sbk.registerServices({
  name: "hello",
  version: "v1",

  actions: {
    hello: {
      rest: {
        method: "GET",
        path: "/hello"
      },

      /**
       * Enable caching to this action
       */
      cache: {

        /**
         * Cache entries expire after 30 seconds.
         * For L1 caching, TTL should be defined as [L2_TTL, L1_TTL].
         * Example: ttl: [60, 10] → L2 TTL is 60 seconds and L1 TTL is 10 seconds.
         */      
        ttl: 30
      },
      handler(ctx){
        return "Hello Samanbayaka"
      }
    },
    welcome: {
      rest: "GET /welcome",
      handler(ctx) {
        return `Welcome, ${ctx.params.query?.name || "Guest"} - ${ctx.broker.nodeID}`
      }
    },
  },
})

Create auxaliary broker services

for producer
mkdir <your_service_name>-<type>-<topic>
cd <your_service_name>-<type>-<topic>
pnpm init
pnpm install samanbayaka
touch index.mjs

An auxiliary service, such as a producer that publishes messages to the STUDENT topic, can be created as follows:

mkdir producer-kafka-student
cd producer-kafka-student
pnpm init
pnpm install samanbayaka
touch index.mjs

Open index.mjs and paste the following:

import sbk from "samanbayaka"
await sbk.registerBridgeServices(
  "kafka",
  {
    name: "producer-kafka-student", 
    rest: true,
    ...
  }, 
  () => {}
)

In the service configuration name end with "*" i.e. producer-kafka-student* can capable to publish to the all topics start with STUDENT like STUDENT.SCIENCE, STUDENT.ARTS etc.

name: "producer-kafka-student*"

If you do not expose the service as a REST API and run it as a private/internal service, either remove the rest property or set it to false.

rest: false

for consumer

mkdir <your_service_name>-<type>-<topic>-<group>
cd <your_service_name>-<type>-<topic>-<group>
pnpm init
pnpm install samanbayaka
touch index.mjs

An auxiliary service, such as a consumer that subscribe messages from the STUDENT topic having group name junior, can be created as follows:

mkdir consumer-kafka-student-junior
cd consumer-kafka-student-junior
pnpm init
pnpm install samanbayaka
touch index.mjs

Open index.mjs and paste the following:

import sbk from "samanbayaka"
await sbk.registerBridgeServices(
  "kafka",
  {
    name: "consumer-kafka-student", 
    consumer: {
      groupId: "junior",
      interMessageDelayMs: 10,
      ...
    },
    ...
  }, 
  () => {}
)

The interMessageDelayMs option introduces a delay between two consecutive message/event consumptions, measured in milliseconds. If you do not need any delay between message consumption, simply remove the interMessageDelayMs property from the consumer options.


Run the services

  • development/testing
cd <your_path>/gateway
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.mjs
cd <your_path>/hello
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.mjs

or

rm -rf node_modules/samanbayaka/ &&cp -r ../../samanbayaka/. node_modules/samanbayaka/ && SBK_CONFIG_CRED='sbk sbk@123 12379' node index.mjs

pm2 stop "$(basename "$PWD")" && rm -rf node_modules/samanbayaka/ &&cp -r ../../samanbayaka/. node_modules/samanbayaka/ && SBK_CONFIG_CRED='sbk sbk@123 12379' pm2 start index.mjs --name "$(basename "$PWD")" --stop-exit-codes 1 --output /var/log/samanbayaka/sbk-out-${HOSTNAME}-$$.log --error /var/log/samanbayaka/sbk-err-${HOSTNAME}-$$.log
  • production
cd <your_path>/gateway
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.mjs >> /var/log/samanbayaka/sbk-${HOSTNAME}-$$.log 2>&1
cd <your_path>/hello
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.mjs >> /var/log/samanbayaka/sbk-${HOSTNAME}-$$.log 2>&1

or

cd <your_path>/gateway
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' pm2 start index.mjs --name "$(basename "$PWD")" --stop-exit-codes 1 --output /var/log/samanbayaka/sbk-out-${HOSTNAME}-$$.log --error /var/log/samanbayaka/sbk-err-${HOSTNAME}-$$.log
cd <your_path>/hello
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' pm2 start index.mjs --name "$(basename "$PWD")" --stop-exit-codes 1 --output /var/log/samanbayaka/sbk-out-${HOSTNAME}-$$.log --error /var/log/samanbayaka/sbk-err-${HOSTNAME}-$$.log

Demo

You can also run the demo service to better understand how microservices work in the Moleculer ecosystem and how REST APIs are exposed.

mkdir demo
cd demo
pnpm init
pnpm install samanbayaka
touch demo.mjs

Open and edit the demo.mjs file as follows

import sbk from "samanbayaka"
await sbk.loadDemo()

Run the service, demo

node demo.mjs

Dockers

Etcd

To manage configurations centrally, use the docker-compose.yml file to run Etcd and All .yml configuration files must be deployed to /usr/local/etc/<your_project_name>.

mkdir -p etcd
cd etcd
touch docker-compose.yml
export ETCD_ROOT_PW=<your_root_pass>
export ETCD_CONFIG_ADMIN_PW=<your_config_admin_pass>
sudo mkdir -p /usr/local/etc/<your_project_name>

Open docker-compose.yml and paste the following:

services:
  etcd:
    image: quay.io/coreos/etcd:v3.5.5
    container_name: sbk-etcd

    ports:
      - "<your_api_port>:2379"
      - "<your_cluster_port>:2380"

    volumes:
      - /usr/local/etc/<your_project_name>:/etcd-data

    command:
      - /usr/local/bin/etcd
      - --name=etcd
      - --data-dir=/etcd-data
      - --listen-client-urls=http://0.0.0.0:2379
      - --advertise-client-urls=http://etcd:2379
      - --listen-peer-urls=http://0.0.0.0:2380
      - --initial-advertise-peer-urls=http://etcd:2380
      - --initial-cluster=etcd=http://etcd:2380
      - --initial-cluster-state=new

    restart: unless-stopped

  etcd-init:
    image: quay.io/coreos/etcd:v3.5.5
    depends_on:
      - etcd

    volumes:
      - /usr/local/etc/<your_project_name>:/etcd-data

    environment:
      - ETCDCTL_API=3

    entrypoint: 
      - /bin/sh
      - -c

    command:
      - |
        set -e

        echo "waiting for etcd..."

        for i in $(seq 1 30); do
          etcdctl --endpoints=http://etcd:2379 endpoint health && break
          echo "retry $$i..."
          sleep 2
        done

        echo "etcd initialized"

        echo "Creating the root role"
        etcdctl --endpoints=http://etcd:2379 role add root || true

        echo "Creating the root user"
        etcdctl --endpoints=http://etcd:2379 user add root:${ETCD_ROOT_PW} || true

        echo "Granting the root role to the root user"
        etcdctl --endpoints=http://etcd:2379 user grant-role root root

        echo "Enable authentication"
        etcdctl --endpoints=http://etcd:2379 auth enable || true

        # -------------------------------------------------------

        echo "Creating admin role"
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add admin

        echo "Granting broad permissions"
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true admin readwrite /

        echo "Creating configadmin user"
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add configadmin:${ETCD_CONFIG_ADMIN_PW}

        echo "Assign role"
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role configadmin admin

        # ---------------------------------------------------------

        echo "Creating Roles and Granting"

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add default
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true default read /config/sbk/global/
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true default read /config/sbk/members/

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add edge
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true edge read /config/sbk/edge/

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add bridge
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true bridge read /config/sbk/bridge/

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add sap
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true sap read /config/sbk/sap/

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add dbs
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true dbs read /config/sbk/dbs/

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add msg
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true msg read /config/sbk/msg/

        # ---------------------------------------------------------
        
        echo "Creating User and Assign Role"

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add sbk:<your_pass>
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role sbk default

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add apigw:<your_pass>
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role apigw default
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role apigw edge

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add msgbus:<your_pass>
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role msgbus default
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role msgbus bridge

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add sap:<your_pass>
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role sap default
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role sap sap

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add dbs:<your_pass>
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role dbs default
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role dbs dbs

        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add msg:<your_pass>
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role msg default
        etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role msg msg

        # ---------------------------------------------------------
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/sys/yaml/SYS_CONFIGS "$(cat /etcd-data/sysconfig.yml)" || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/REVISION "" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/APP_ENV development || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/LOG_LEVEL warn || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/MAX_L1_TTL 120 || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/MAX_L2_TTL 600 || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/TELEMETRY false || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/broker/yaml/nats "$(cat /etcd-data/nats.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/catcher/yaml/redis "$(cat /etcd-data/redis.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/telemetry/yaml/openobserve "$(cat /etcd-data/openobserve.yml)" || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/edge/yaml/auth "$(cat /etcd-data/auth.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/edge/asset/path public || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/bridge/yaml/kafka "$(cat /etcd-data/kafka.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/bridge/yaml/mqtt "$(cat /etcd-data/mqtt.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/bridge/yaml/amqp "$(cat /etcd-data/amqp.yml)" || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/sap/yaml/isu "$(cat /etcd-data/isu.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/sap/yaml/erp "$(cat /etcd-data/erp.yml)" || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/gisdb "$(cat /etcd-data/gisdb.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/geomdb "$(cat /etcd-data/geomdb.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/acmadb "$(cat /etcd-data/acmadb.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/isudb "$(cat /etcd-data/isudb.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/crmdb "$(cat /etcd-data/crmdb.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/mdasdb "$(cat /etcd-data/mdasdb.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/route-sms "$(cat /etcd-data/route-sms.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/route-otp "$(cat /etcd-data/route-otp.yml)" || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/outlook "$(cat /etcd-data/outlook.yml)" || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/demo true || true
        
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system true || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/LOG_LEVEL error || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/MAX_L1_TTL 0 || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/MAX_L2_TTL 0 || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/gateway true || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/gateway/envs/PORT 8765 || true

        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/test true || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/sms add || true
        etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/email add || true

        #etcdctl --endpoints=http://etcd:2379 --user=<your_user>:<your_pass> get /config/sbk/ --prefix
        #etcdctl --endpoints=http://etcd:2379 --user=<your_user>:<your_pass> get /config/sbk/global/app_env

        echo "etcd initialization completed"

Optionally verify:

docker ps | grep 'sbk-etcd'

Optionally check health:

docker exec -it sbk-etcd etcdctl --endpoints=http://etcd:2379 endpoint health