Skip to main content

@crypto-asset-custody/core

Core structures.

App

uWS based application frameworks. Wrappers basically(not so basic though).

App Engine

A basic class for app initialization and running services. You can define startup tasks and pass a worker app to start.

Worker Apps

Worker apps that run inside app engine.

Web App

uWS HTTP server wrapper framework. You can create new pipelines for requests to follow. Pipeline components are:

  • middleware
    • pre: Middlewares that should run before the request passed to controller. Like authenticator, body parser, etc.
    • post: Middlewares that should run after the request passed to controller. Like request response logging, creating data points for metrics.
  • controller: Accepts an orchestrator in build step. You can add pre-post processing callbacks. To manipulate input or output etc.
  • orchestrator: A function that returns some data. The returned data will appear on response body. You can return promise, observable or data object itself.
Callback Builder

Callback builder is the core of the request flow. For each route a controller must be passed to generate the request handler. Websocket route support is included, please check code for details.

You can define API specifications to control the API response standard, error handling behaviour.

Business Access

Rabbit

RabbitMQ service implementation. Provides an easier interface to handle tasks. If a task fails during processing it should throw and the task will be placed to <original_queue>/fallback queue for extensive re-processing. This way, no message will be processed twice and processing loops are prevented. Connection terminations are handled gracefully.

To prevent user errors, tasks are pre-defined and validated before pushed into RabbitMQ.

Redis

Redis service implementation. Simpler functions are defined for different data structures of redis.

Data Structures

  • atomic: Define complex atomic instructions with Lua scripts.
  • hashTable: Redis hash table functions.
  • sortedSet: Redis sorted set functions.
  • list: Redis list functions.
  • string: Redis string functions.
  • stream: Redis stream functions.
  • sorted_set_expire: Custom data structure with tweaked usage of native sorted set data structure.

Interfaces

Patterns for different use cases. Listed under interface property of a client instance.

  • id: Id generation interface.
  • cache_recovery: App cache recovery interface, in case of loader initialization errors.
  • state_recovery: Some objects need to store their states between service restarts. You can use this interface to store the states.

Publisher

Creates a redis publisher client instance with a restricted method set. Executing regular redis commands with these instances are prevented. Channel name is set on instantiation, application environment automatically inserted to prevent collision between environments.

Subscriber

Creates a redis publisher client instance with a restricted method set. Executing regular redis commands with these instances are prevented. Channel name is set on instantiation, application environment automatically inserted to prevent collision between environments. You must attach a callback for message handling.

Data Access

Database operation center.

Core

Provides an easy way to manage pools and queries. Custom error handling capability.

Repositories

Function sets for different tables are implemented here. You can write these objects in the service that use this package too.

Errors

Error registry. Must be initialized from cache on startup. Each error is injected into errors object. So you can write throw errors.ERR_CODE() and let the error fields filled from properties from registry stored in database.

Services

Cache

App cache. Fully in memory. For mostly static objects in database. Also, can be used to store data from random requests.

For the most simple case, you use a loader to load a database table entries into your memory. But you can create more complex flows to extend the caches' capability.

Cached objects might have dependencies to each other and, you might want to use another cached object during the other cached objects' loader function. For these cases you can set which loader is dependent to which other loader. App cache will generate a dependency graph and use topological sorting to decide which loader to run in which initialization round. If you create a cyclic loader configuration, cache will interrupt the initialization process.

Loaders

Template initialization function set for each cache entry.

Pg Observer

Connects to change relay service and listens the versions of each cached data entry. At each update it will ping cache to trigger loader function.

Secret Manager

Secret manager implementation with multiple provider support. Currently two provider support is implemented.

  • Infisical (development in-progress)
  • Openbao

In order to load a secret on startup you should set the related config field in following format.

Application config is parsed recursively and any field that matches the following format will be replaced with the secret value loaded from the secret provider.

@<provider>:<secret_path>:<object_path>
  • provider: infisical or openbao
  • secret_path: Must start with /. (/my_example_secret)
  • object_path: Dot separated object path. for secret_object[my][object][path] you should write my.object.path
Example

Example secret object stored at /my_example_secret path. Like below.

{
"my": {
"example": {
"secret_1": "abba",
"secret_2": "boney m."
}
}
}

To load this secret you can put the following strings to any field in your config file. Like below.

{
"api_key": "@openbao:/my_example_secret:my.example.secret_1",
"google": {
"api_key": "@openbao:/my_example_secret:my.example.secret_2"
}
}

The config above will be parsed and matched formats will be replaced with secret values loaded from provider.

Socket Interface

Base socket interface class that cover basic initialization tasks. Depending on your use case you can extend this class and overload the member methods.

ZNS

An inter-service communication layer. Handles the service discovery. Service registry is stored in database. Services reference each other with codes rather than ips and port numbers. Makes the overall communication paths between services more dynamic and cloud environment agnostic.