# @exporo/tscircle-framework

> This package contains the core code of the tscircle framework.

Latest version **0.0.1-1** (published 2021-06-23) · MIT license · 0 weekly downloads

## Install

```sh
npm install @exporo/tscircle-framework
pnpm add @exporo/tscircle-framework
yarn add @exporo/tscircle-framework
bun add @exporo/tscircle-framework
```

## Health

**Score 25/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities; high quality score.

Warnings: low downloads; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.0.1-1 |
| Published | 2021-06-23 |
| First published | 2021-06-23 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 25 |
| Unpacked size | 211.5 KB |
| Known vulnerabilities | 0 (+3 in 3 direct dependencies) |
| Install scripts | no |
| Author | Exporo |
| Maintainers | exporo_rpranjic, swetzel, tiagor0424, psclahr, ldomingos |

## Links

- npm: https://www.npmjs.com/package/@exporo/tscircle-framework
- npm.io page: https://npm.io/package/@exporo/tscircle-framework

## Dependencies (25)

- [glob](https://npm.io/package/glob.md) ^7.1.6
- [knex](https://npm.io/package/knex.md) ^0.19.4
- [middy](https://npm.io/package/middy.md) ^0.33.2
- [mocha](https://npm.io/package/mocha.md) ^6.2.1
- [mysql](https://npm.io/package/mysql.md) ^2.17.1
- [tslib](https://npm.io/package/tslib.md) ^1.10.0
- [lodash](https://npm.io/package/lodash.md) ^4.17.15
- [xstate](https://npm.io/package/xstate.md) ^4.7.2
- [aws-sdk](https://npm.io/package/aws-sdk.md) ^2.578.0
- [express](https://npm.io/package/express.md) ^4.17.1
- [jwks-rsa](https://npm.io/package/jwks-rsa.md) ^1.6.0
- [@hapi/joi](https://npm.io/package/@hapi/joi.md) ^16.1.4
- [formidable](https://npm.io/package/formidable.md) ^1.2.1
- [typescript](https://npm.io/package/typescript.md) ^3.6.3
- [@types/chai](https://npm.io/package/@types/chai.md) ^4.2.2
- [@types/knex](https://npm.io/package/@types/knex.md) ^0.14.26
- [@types/node](https://npm.io/package/@types/node.md) ^12.7.5
- [es6-request](https://npm.io/package/es6-request.md) ^3.0.5
- [http-errors](https://npm.io/package/http-errors.md) ^1.7.3
- [@types/mocha](https://npm.io/package/@types/mocha.md) ^5.2.7
- [esserializer](https://npm.io/package/esserializer.md) ^1.0.0
- [@types/lodash](https://npm.io/package/@types/lodash.md) ^4.14.149
- [knex-paginate](https://npm.io/package/knex-paginate.md) ^1.2.1
- [serverless-http](https://npm.io/package/serverless-http.md) ^2.3.0
- [@slynova/flydrive](https://npm.io/package/@slynova/flydrive.md) ^0.3.1

## Recent versions

- 0.0.1-1 (latest) — 2021-06-23
- 0.0.1-0 — 2021-06-23

## README

# tscircle/framework

This repository contains the core code of the tscircle framework.
[Here](https://github.com/tscircle/boilerplate) is boilerplate to run this framework.

[![CircleCI](https://circleci.com/gh/tscircle/framework.svg?style=svg)](https://circleci.com/gh/tscircle/framework)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=tscircle_framework&metric=alert_status)](https://sonarcloud.io/dashboard?id=tscircle_framework)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=tscircle_framework&metric=coverage)](https://sonarcloud.io/dashboard?id=tscircle_framework)
[![Known Vulnerabilities](https://snyk.io/test/github/tscircle/framework/badge.svg?targetFile=package.json)](https://snyk.io/test/github/tscircle/framework?targetFile=package.json)

## local development

```
docker-compose up -d
docker-compose exec node bash
$docker:npm install
$docker:npm npm run tests
```

## Database

application/domain/users/models/user.model.ts

```
User.q().where('column', '=', 'foo').first().then((column) => {});

User.updateOrCreate(['column', 'foo'], ['column2', 'newValue']);

User.find(1).then((item) => {});
```

### Migration commands

```
$npm run migrate:make my_table_creation_description

$npm run migrate:make migrate:latest

$npm run migrate:make migrate:rollback
```

In the background knex is used.

## Storage

In the local development environment, the local ./storage folder is used and in an AWS environment the S3 the bucket, created in the Cloudformation script, is used.
[Flydrive](https://github.com/Slynova-Org/flydrive) is used as filesystem abstraction manager.

```
import {Storage} from '@tscricle/framework/storage/storage';

Storage.put('message.txt', 'Hello Node');

Storage.get('message.txt').then((content)=> {console.log(content.toString())});
```

## Cache

The docker container amazon/dynamodb-local is used locally. In an AWS environment the generated DynamoDB table is used.

```
import {Cache} from '@tscricle/framework/cache/cache';

const ttlInSeconds = 60;

Cachce.remember('cache-key', ttlInSeconds, () => { return 'cache-valuee'});
```

## Queue

The docker container vsouza/sqs-local is used locally. In an AWS environment the generated SQS queue together with a dead letter queue is used.

```
import {Queue} from "@tscricle/framework/queue/queue";
import {myJOb} from "../application/jobs/myJob";

return Queue.dispatch(myJOb, {email: 'test'});
```

TODO improve tests

## BaseModel

https://github.com/tscircle/framework/blob/master/model/baseModel.ts

## BaseRepository

https://github.com/tscircle/framework/blob/master/repository/baseRepository.ts

## Base Controller

https://github.com/tscircle/framework/blob/master/http/controllers/baseController.ts

The base controller automatically calls the handler method.

```
functions:
  userRestEndpoint:
    handler: application/domain/user/controllers/userDownloadController.restHandler
    events:
    - http:
        path: /users/download
        method: GET
```

```
import {BaseController} from '@tscricle/framework/http/controllers/baseController';
export class EmailSpecialController extends BaseController {

    constructor() {
        super();
    }

}

exports.restHandler = new EmailSpecialController().setupRestHandler();
```

Validation can be done like this:

```
validationSchema = Joi.object().keys({
   name: Joi.string().alphanum().min(3).max(30).required(),
});
```

## CRUD Controller

https://github.com/tscircle/framework/blob/master/http/controllers/crudController.ts
The crud controller automatically performs crud operations on the provided model.

```
functions:
  userRestEndpoint:
    handler: application/domain/users/controllers/userController.restHandler
    events:
    - http:
        path: /users/{id}
        method: ANY
    - http:
        path: /users
        method: ANY
```

```
import {CrudController} from '@tscricle/framework/http/controllers/crudController';
import { UserRepository } from "../repositories/userRepository";

export class UserController extends CrudController {
    constructor() {
        super(new UserRepository());
    }
```

Be careful because the ApiGateway from AWS groups the endpoints by segments, so the same parameters of "/company/{parentId}" and "/company/{parentId}/user/{userId}" like "parentId" cannot be named differently.
**Also in such a case "/company/{parentId}/user/{userId}" the first parameter must always be "parentId".**

```
companyRestEndpoint:
  handler: application/domain/company/controllers/companyController.restHandler
  events:
  - http:
      path: /company/{parentId}
      method: ANY
      cors: true
  - http:
      path: /company
      method: ANY
      cors: true

useCompanyRestEndpoint:
  handler: application/domain/company/controllers/companyUserController.restHandler
  events:
  - http:
      path: /company/{parentId}/user/{userId}
      method: ANY
      cors: true
  - http:
      path: /company/{parentId}/user
      method: ANY
      cors: true

```

By default the following routes are created and the corresponding functions are called:

```
${route}/ =>  this.index
${route}/:id => this.show
${route}/ => this.store
${route}/:id => this.update
${route}/:id => this.remove
```

Validation can be done like this:

```
onStoreValidationSchema = userSchema;
onUpdateValidationSchema = editUserSchema;
}
```

To handle the lambda response from the extended CrudController class the property hasHandleResponse should be set to true

```
// controller.ts
export class Controller extends CrudController {
  hasHandleResponse = true; //default: false
  ...
}
// repository.ts
  ...
  public async get(id: number, parentId?: number | undefined, event?: APIGatewayProxyEvent | undefined) {

    return {
        body: string,
        statusCode: 200
    }
  }
  ...
}
```

Custom Routes can be added like this:

```
functions:
  userRestEndpoint:
    handler: application/domain/users/controllers/userController.restHandler
    events:
    - http:
        path: /clients/{id}/wallets/fees/
        method: ANY
    - http:
        path: /clients/{id}/profile/uploadProfilePicture
        method: ANY
```

```
import {CrudController} from '@tscricle/framework/http/controllers/crudController';
import { UserRepository } from "../repositories/userRepository";

export class UserController extends CrudController {
    constructor() {
        super(new UserRepository());

		get customRoutes(): CustomRoute[] {
          return [
            {
                route: '/clients/{id}/wallets/fees/',
                httpMethod: 'GET',
                method: this.getWalletsFees
            },
            {
                route: '/clients/{id}/profile/uploadProfilePicture',
                httpMethod: 'POST',
                method: this.uploadProfilePicture
            }
          ]
	    }

		private getWalletsFees(event) {}
		//for files handler use multipart/form-data
		private uploadProfilePicture(event) {}
    }
```

## State Machine

There is an abstract state machine that can be easily implemented.
The state machine is automatically persisted and rehydrated by the database.
This State Machine libraray is used: https://xstate.js.org/
Here you can find the abstract state machine:
https://github.com/tscircle/framework/blob/master/stateMachine/stateMachine.ts

Database:
When creating an instance and executing a transition, the entry in the database is automatically changed.
There are two tables: state_machine records the current state of all state machine instances.
The table state_machine_history contains every change to a state machine.

To use own tables smRepository and smHistoryRepository can be overwritten in the implementation with own repositories.

```
protected smRepository: StateMachineRepository = new StateMachineRepository();
protected smHistoryRepository: StateMachineHistoryRepository = new StateMachineHistoryRepository();
```

Here is an example implementation:

```
export interface ProcessContext {
    amount: number;
    type: string;
}

export class processStateMachine extends stateMachine {

    public async create(context: ProcessContext) {
        return super.create(context);
    }

    protected config: MachineConfig<ProcessContext, any, any> = {
        id: 'quiet',
        initial: 'start',
        context: {
            amount: 0,
            type: ' yeah'
        },
        states: {
            start: {
                on: {
                    NEXT: 'waiting'
                }
            },
            waiting: {
                on: {
                    NEXT: 'paid'
                }
            },
            paid: {
                on: {
                    NEXT: 'finished'
                }
            },
            finished: {
                type: 'final'
            }
        }
    };
}
```

To create a new State Machine instance:

```
let sm = new processStateMachine();
await sm.create({
    amount: 1000,
    type: 'prepay',
});
```

or to rehydrate the State Machine instance with the ID 12 from the database:

```
let sm = new processStateMachine();
await sm.load(12);
```

The following call returns the instance ID:

```
await sm.getId();
```

To query the status object of an instance:

```
await sm.getStatus();
```

To execute a transition of the instance:

```
await sm.transition('NEXT');
```

---
_Source: https://npm.io/package/@exporo/tscircle-framework · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
