master 2b7f4ee9959f cached
99 files
95.4 KB
27.9k tokens
37 symbols
1 requests
Download .txt
Repository: pankod/moleculerjs-boilerplate
Branch: master
Commit: 2b7f4ee9959f
Files: 99
Total size: 95.4 KB

Directory structure:
gitextract_izw2cz6n/

├── .dockerignore
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── .travis.yml
├── Dockerfile
├── LICENSE
├── README.md
├── db.sqlite.example
├── docker-compose.env
├── docker-compose.yml
├── documentation/
│   ├── Dockerfile
│   ├── README.md
│   ├── docker-compose.yml
│   ├── docs/
│   │   ├── cli-migration-guide.md
│   │   ├── cli-overview.md
│   │   ├── cli-usage.md
│   │   ├── deployment.md
│   │   ├── eslint.md
│   │   ├── example.md
│   │   ├── features.md
│   │   ├── getting-started.md
│   │   ├── setup.md
│   │   ├── structure.md
│   │   ├── swagger.md
│   │   ├── testing.md
│   │   └── typeorm.md
│   └── website/
│       ├── config.yml
│       ├── core/
│       │   └── Footer.js
│       ├── docs.json
│       ├── i18n/
│       │   └── en.json
│       ├── package.json
│       ├── pages/
│       │   └── en/
│       │       ├── help.js
│       │       ├── index.js
│       │       └── users.js
│       ├── sidebars.json
│       ├── siteConfig.js
│       └── static/
│           └── css/
│               └── custom.css
├── moleculer.config.ts
├── package.json
├── public/
│   └── index.html
├── services/
│   ├── api.service.ts
│   ├── attack.service.ts
│   ├── index.ts
│   └── planet.service.ts
├── src/
│   ├── Entities/
│   │   ├── Connection.ts
│   │   ├── Planet.ts
│   │   ├── Weapon.ts
│   │   └── index.ts
│   ├── Interfaces/
│   │   ├── Meta/
│   │   │   ├── DamageMetaOutDto.d.ts
│   │   │   └── index.ts
│   │   ├── Repositories/
│   │   │   ├── Planet/
│   │   │   │   ├── DecreaseShieldOutDto.d.ts
│   │   │   │   └── index.ts
│   │   │   └── Weapon/
│   │   │       ├── DecreaseAmmoOutDto.d.ts
│   │   │       └── index.ts
│   │   ├── Services/
│   │   │   ├── Attack/
│   │   │   │   ├── IAttack.d.ts
│   │   │   │   └── index.ts
│   │   │   └── Planet/
│   │   │       ├── IPlanet.d.ts
│   │   │       └── index.ts
│   │   └── index.ts
│   ├── Meta/
│   │   ├── CalculateMeta.ts
│   │   └── index.ts
│   ├── Repositories/
│   │   ├── ErrorHelpers.ts
│   │   ├── Planet.ts
│   │   ├── Shared.ts
│   │   ├── Weapon.ts
│   │   └── index.ts
│   └── ServiceHelpers/
│       ├── AttackHelper.ts
│       ├── PlanetHelper.ts
│       └── index.ts
├── swagger/
│   ├── config.js
│   ├── index.js
│   ├── package.json
│   └── swagger.json
├── swaggerConfig.json
├── test/
│   ├── Config/
│   │   ├── Connection.ts
│   │   ├── SetupDatabase.ts
│   │   └── mock.setup.ts
│   ├── Integration/
│   │   ├── attack.spec.ts
│   │   └── planet.spec.ts
│   ├── Seeder/
│   │   ├── AttackSeeder.ts
│   │   ├── PlanetSeeder.ts
│   │   └── index.ts
│   ├── Unit/
│   │   ├── Entities/
│   │   │   └── Connection.spec.ts
│   │   ├── Meta/
│   │   │   └── CalculateMeta.spec.ts
│   │   ├── MicroServices/
│   │   │   ├── attack.spec.ts
│   │   │   └── planet.spec.ts
│   │   ├── Repositories/
│   │   │   ├── ErrorHelpers.spec.ts
│   │   │   ├── Planet.spec.ts
│   │   │   └── Weapon.spec.ts
│   │   └── ServiceHelpers/
│   │       ├── AttackHelper.spec.ts
│   │       └── PlanetHelper.spec.ts
│   └── Utils/
│       ├── BrokerHelper.ts
│       ├── DummyContext.spec.ts
│       ├── DummyContext.ts
│       └── index.ts
├── tsconfig.json
└── tsconfig.production.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
node_modules
dist
project-cli
documentation


================================================
FILE: .editorconfig
================================================
root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = tab
indent_size = 4

[package.json]
indent_style = space
indent_size = 2


================================================
FILE: .eslintrc.js
================================================
module.exports = {
	parser: '@typescript-eslint/parser',
	extends: [
		'plugin:@typescript-eslint/recommended',
		'prettier/@typescript-eslint',
		'plugin:prettier/recommended',
	],
	parserOptions: {
		ecmaVersion: 2018,
		sourceType: 'module',
		project: './tsconfig.json',
	},
	rules: {
		// Disabled Rules
		'@typescript-eslint/camelcase': ['error', { properties: 'never' }],
		'@typescript-eslint/explicit-function-return-type': 'off',
		'@typescript-eslint/explicit-member-accessibility': 'off',
		'@typescript-eslint/interface-name-prefix': 'off',
		'@typescript-eslint/no-empty-interface': 'off',
		'@typescript-eslint/no-var-requires': 'off',
		'@typescript-eslint/no-object-literal-type-assertion': 'off',
		'@typescript-eslint/no-inferrable-types': 'off',
		'@typescript-eslint/no-magic-numbers': 'off',
		'@typescript-eslint/no-namespace': 'off',
		'@typescript-eslint/no-non-null-assertion': 'off',
		'@typescript-eslint/no-type-alias': 'off',
		'@typescript-eslint/no-require-imports': 'off',
		'@typescript-eslint/no-object-literal-type-assertion': 'off',
		'@typescript-eslint/prefer-interface': 'off',
		// Enabled rules
		'@typescript-eslint/adjacent-overload-signatures': 'error',
		'@typescript-eslint/array-type': 'error',
		'@typescript-eslint/await-thenable': 'error',
		'@typescript-eslint/class-name-casing': 'error',
		'@typescript-eslint/member-ordering': 'error',
		'@typescript-eslint/no-explicit-any': 'error',
		'@typescript-eslint/no-triple-slash-reference': 'error',
		'@typescript-eslint/no-unnecessary-type-assertion': 'error',
		'@typescript-eslint/no-unused-vars': 'error',
		'@typescript-eslint/no-unnecessary-qualifier': 'error',
		'@typescript-eslint/no-parameter-properties': 'error',
		'@typescript-eslint/no-misused-new': 'error',
		'@typescript-eslint/no-for-in-array': 'error',
		'@typescript-eslint/no-angle-bracket-type-assertion': 'error',
		'@typescript-eslint/no-var-requires': 'error',
		'@typescript-eslint/prefer-function-type': 'error',
		'@typescript-eslint/promise-function-async': 'error',
		'@typescript-eslint/restrict-plus-operands': 'error',
		'@typescript-eslint/semi': 'error',
		'@typescript-eslint/type-annotation-spacing': 'error',
		'@typescript-eslint/unified-signatures': 'error',
		complexity: ['error', { max: 3 }],
		'max-depth': ['error', { max: 4 }],
		'prefer-const': [
			'error',
			{
				destructuring: 'all',
				ignoreReadBeforeAssign: true,
			},
		],
	},
};


================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# history
.history

# sqlite
db.sqlite

# macos
.DS_Store

# builds
/project-cli/dist
dist/
/documentation/website/build

# webstorm
.idea/
*.iml


================================================
FILE: .prettierrc
================================================
{
	"semi": true,
	"trailingComma": "all",
	"singleQuote": true,
	"printWidth": 100,
	"tabWidth": 4,
	"useTabs": true
}


================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
  - "10"
install:
  - npm ci
script:
  - npm run lint
  - npm run test
before_script:
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
  - chmod +x ./cc-test-reporter
  - ./cc-test-reporter before-build
after_success:
  - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT


================================================
FILE: Dockerfile
================================================
FROM node:10-alpine

RUN mkdir /app
WORKDIR /app

COPY package*.json ./

RUN npm ci 

COPY . .

RUN npm run build && npm prune --production

ENV NODE_ENV=production
CMD ["npm", "start"]


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Pankod

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<img src="moleculerjs-cover.png" alt="Moleculer JS Microservice Boilerplate with Typescript, TypeORM, CLI, Service Clients, Swagger, Jest, Docker, Eslint support and everything you will ever need to deploy rock solid projects." align="center" />

<br/>
<div align="center" >Moleculer JS Microservice Boilerplate with Typescript, TypeORM, CLI, Service Helpers, Swagger, Jest, Docker, Eslint support and everything you will ever need to deploy rock solid projects..
</div>
<br/>

<div align="center">
  <!-- CodeClimate -->
  <a href="https://codeclimate.com/github/pankod/moleculerjs-boilerplate/maintainability">
    <img src="https://api.codeclimate.com/v1/badges/077c02d5cb9ec7d8a654/maintainability" />
  </a>
  <!-- CodeCoverave -->
  <a href="https://codeclimate.com/github/pankod/moleculerjs-boilerplate/test_coverage"><img src="https://api.codeclimate.com/v1/badges/077c02d5cb9ec7d8a654/test_coverage" /></a>
  <!-- Build Status -->
  <a href="https://travis-ci.org/pankod/moleculerjs-boilerplate">
    <img src="https://travis-ci.org/pankod/moleculerjs-boilerplate.svg?branch=master" alt="Build Status" />
  </a>
  <!-- Dependency Status -->
  <a href="https://david-dm.org/pankod/moleculerjs-boilerplate">
    <img src="https://david-dm.org/pankod/moleculerjs-boilerplate.svg" alt="Dependency Status" />
  </a>
  <!-- devDependency Status -->
  <a href="https://david-dm.org/pankod/moleculerjs-boilerplate#info=devDependencies"> 
    <img src="https://david-dm.org/pankod/moleculerjs-boilerplate/dev-status.svg" alt="devDependency Status" />
  </a>
</div>

<br/>
<div align="center">
  <sub>Created by <a href="https://www.pankod.com">Pankod</a></sub>
</div>



## About

A microservice is a single self-contained unit which, together with many others, makes up a large application. By splitting your app into small units every part of it is independently deployable and scalable, can be written by different teams and in different programming languages and can be tested individually.

Moleculer is a fast, modern and powerful microservices framework for Node.js. It helps you to build efficient, reliable & scalable services.

This boilerplate make it easier to get started with a well-structured Node.js microservices with Typescript.

<br/>

## Features


This boilerplate includes the latest powerfull tools.

* **Moleculer** - Moleculer is a fast, modern and powerful microservices framework for Node.js.
* **Typescript** - Superset of JavaScript which primarily provides optional static typing, classes and interfaces. path support(allias)
* **Built-in Project CLI**- Create services, entities, interfaces, and tests with one command by using built-in cli.
* **Docker** - A tool designed to make it easier to create, deploy, and run applications by using containers.
* **Eslint** - The pluggable linting utility.
* **Swagger** - A framework backed by a large ecosystem of tools that helps developers design, build, document, and consume RESTful Web services.
* **Jest** - Javascript testing framework , created by developers who created react
* **TypeORM** - TypeORM is specifically an ORM that converts data between JavaScript / TypeScript to a variety of databases.
* **Service Helpers** - Provides easy communication contract between services.
<br/>


## Setup & Documentation

Please refer to our [setup guide](https://pankod.github.io/moleculerjs-boilerplate/docs/setup) to create a new app. 


For more detailed documentation, check out https://pankod.github.io/moleculerjs-boilerplate/

<br/>

## Built-in CLI


<div>
 <img width="600" src="./cli.gif" >
</div>
<br/>
<br/>

moleculerjs-boilerplate is shipped with a CLI tool to streamline the creation of new microservices. By using the CLI tool, you may easily add entities, services to your project and have all the required interfaces and imports are automatically created for you.
<br />

To start the CLI, you may run the following npm command:

```
npm run cli
```


After answering questions it generates files in miliseconds.

<br/>

 
## License

Licensed under the MIT License, Copyright © 2019-present Pankod


================================================
FILE: docker-compose.env
================================================
NAMESPACE=
LOGGER=true
LOGLEVEL=info
SERVICEDIR=dist/services

TRANSPORTER=nats://nats-server:4222



================================================
FILE: docker-compose.yml
================================================
version: "3.0"

services:

  api:
    build: .
    image: api
    env_file: docker-compose.env
    environment:
      SERVICES: api
      PORT: 3000
    ports:
      - "3000:3000"

  attack:
    build: .
    image: attack
    env_file: docker-compose.env
    environment:
      SERVICES: attack

  planet:
    build: .
    image: planet
    env_file: docker-compose.env
    environment:
      SERVICES: planet

  nats-server:
    image: nats:latest
    ports:
      - "4222:4222"


================================================
FILE: documentation/Dockerfile
================================================
FROM node:8.11.4

WORKDIR /app/website

EXPOSE 3000 35729
COPY ./docs /app/docs
COPY ./website /app/website
RUN yarn install

CMD ["yarn", "start"]


================================================
FILE: documentation/README.md
================================================
<img src="https://github.com/pankod/docusaurus-boilerplate/blob/master/demo.png" alt="Pankod - docusaurus-boilerplate" align="center" />

This website was created with [Docusaurus](https://docusaurus.io/).

# What's In This Document

* [Get Started in 5 Minutes](#get-started-in-5-minutes)

# Get Started in 5 Minutes

1. Go to the website folder:

```sh
# Go to the folder
$ cd website
```

2. Make sure all the dependencies for the website are installed:

```sh
# Install dependencies
$ npm i
```

3. Run your dev server:

```sh
# Start the site
$ npm start
```


================================================
FILE: documentation/docker-compose.yml
================================================
version: "3"

services:
  docusaurus:
    build: .
    ports:
      - 3000:3000
      - 35729:35729
    volumes:
      - ./docs:/app/docs
      - ./website/blog:/app/website/blog
      - ./website/core:/app/website/core
      - ./website/i18n:/app/website/i18n
      - ./website/pages:/app/website/pages
      - ./website/static:/app/website/static
      - ./website/sidebars.json:/app/website/sidebars.json
      - ./website/siteConfig.js:/app/website/siteConfig.js
    working_dir: /app/website


================================================
FILE: documentation/docs/cli-migration-guide.md
================================================
---
id: cli-migration-guide
title: CLI Migrate Guide
sidebar_label: Migration Guide
---

Initially, moleculer's `project-cli` was inside the boilerplate repository. This makes it hard to upgrade cli version for users. We decided to move project cli to it's own package. 

This guide will walk you through migrating to new cli.

If you have `@pankod/pankod-cli` in your devDependencies, you can skip this guide.

- Remove `project-cli` folder completely. (`rm -rf project-cli`)
- npm install -D @pankod/pankod-cli

- Add this to your package.json;

```
"pankod": {
  "projectType": "moleculer"
},
```
- Update your `cli` script in `package.json`;

```
"cli": "pankod-cli add",
```

That's it! Now you should be able to use new cli, add Entity or Service.


================================================
FILE: documentation/docs/cli-overview.md
================================================
---
id: cli-overview
title: Overview
sidebar_label: Overview
---


<div>
 <img width="600" src="assets/cli.gif" >
</div>
<br/>
<br/>


moleculerjs-boilerplate is shipped with a CLI tool to streamline the creation of new microservices. By using the CLI tool, you may easily add entities, services, tests to your project and have all the required interfaces and imports are automatically created for you.
<br />

To start the CLI, you may run the following npm command:

```sh
npm run cli
```

After answering the questions, it will generate files in miliseconds.


================================================
FILE: documentation/docs/cli-usage.md
================================================
---
id: cli-usage
title: Usage
sidebar_label: Usage
---


After starting, an interactive menu will let you file to be created. Firstly, you'll be asked for the type of the files whether it's a entity or service. Then you'll be prompted with the other options relevant to your selection.

For example, let's go through the steps of the creation of a service.

>Enter service name

 - Enter the desired filename for the service. Spaces are not allowed!
 - The tool will check for the existing filenames in the project and reject if found any.

>Is service open to outside?

- If you choose yes, cli adds swagger tags to service file. 

>Are you going to have a database?
 - If yes, it adds `connectionInstance` method and import to service file.


After answering questions it generates files and set imports which specified at the below.

 - Creates new service with given name into services directory.
 - Adds service export into ``services/index.ts`` file.
 - Creates a new interface file in `src/Interfaces/Services` directory.
 - Create index.ts file into service interface folder.
 - Adds file exports into `src/Interfaces/index.ts` file.
 - Adds service import in `test/Utils/BrokerHelper.ts` file.
 - Adds service into setupBroker method in `test/Utils/BrokerHelper.ts` file.
 - Create service helper into `src/ServiceHelper` directory.
 - Adds service into index in `src/ServiceHelper/index.ts` file.
 - Create service helper test into `test/Unit/ServiceHelper` directory.
 - Create service test into `test/Unit/MicroService` directory.
 - Create integration test into `test/Integration` directory.
 

================================================
FILE: documentation/docs/deployment.md
================================================
---
id: deployment
title: Deployment
sidebar_label: Deployment
---

## Build

Builds the app for production into the dist folder.
```sh
npm run build
```

Once you built the app, you can run microservices with;

```sh
npm run start
```

## Docker

If you want to run the app with Docker, we already included `docker-compose.yaml`, `docker-compose.env` files and scripts to start and stop Docker deployment.

To start;
```js
npm run dc:up
```

To stop;
```js
npm run dc:down
```
<br>
> We are using `NATS` for communication between microservices in Docker deployment.

<br>

*docker-compose.yaml*
```
version: "3.0"

services:

  api:
    build: .
    image: api
    env_file: docker-compose.env
    environment:
      SERVICES: api
      PORT: 3000
    ports:
      - "3000:3000"

  attack:
    build: .
    image: attack
    env_file: docker-compose.env
    environment:
      SERVICES: attack

  planet:
    build: .
    image: planet
    env_file: docker-compose.env
    environment:
      SERVICES: planet

  nats-server:
    image: nats:latest
    ports:
      - "4222:4222"
```

Refer to moleculer deployment documentation;

 https://moleculer.services/docs/0.13/deploying.html


================================================
FILE: documentation/docs/eslint.md
================================================
---
id: eslint
title: Usage
sidebar_label: ESLint
---

ESLint integrated to boilerplate for linting.

Lints with Eslint. Useful for CI.
```SH
npm run lint 
```

Lints and fixes fixable problems.
 
```SH
npm run format 
```

>Refer to [offical documentation](https://eslint.org/) for detailed usage.


================================================
FILE: documentation/docs/example.md
================================================
---
id: example-app
title: Example App
sidebar_label: Example App
---
<br>
<img src="assets/alderaan.png" align="center" />

>>>*"The defense systems on Alderaan, despite the Senator's protestations to the contrary, were as strong as any in the Empire. I should conclude that our demonstration was as impressive as it was thorough."*
―Darth Vader


We've integrated microservice example to show how services connect together. The aim of this example is to demonstrate how two different services communicate with each other.

Running `npm run setup-db` will seed the database and create a planet and a weapon. Planet's name is `Alderaan`, weapon's name is `Death Star`.
According to the story, Death Star will try to destroy Alderaan;

- **Death Star**: A weapon to destroy planets.

- **Alderaan**: A planet far far away.

TODO: Death Star is a planet destroyer weapon. It destroyed Alderaan.

## Overview

We have 2 services as seen below;

 - Attack service with **Fire Action** (**api/attack/Fire**)
	
	Death Star will use this service to attack another planet.
 
 - Planet service with **Defend Action** (**api/planet/Defend**)

	Alderaan will use this service to defend itself.

To get more information about **Actions**, visit [Moleculer Documentation](https://moleculer.services/docs/0.13/actions.html)

## Entities:

### Planet
```js
{
	name: 'Alderaan',
	shield: 100000
}
```

### Weapon
```js
{
	name: 'Death Star',
	damage: 1000,
	ammo: 1000
}
```

To get more information about `Entities`, visit [TypeOrm Documentation](https://typeorm.io/#/entities)

## Services

Both services has a structure as seen below. We can make API request to these services;

Let's fire!

### Attack Service

Attack service will get weapon and planet names as parameters. Then it will use this information to make request to Planet service to find out how much damage is done and how much shield planet has left. 
You can see example of calling a service from another service below, in **Communication between services** section.

See example attack request;

```sh
POST http://localhost:3000/api/attack/Fire

Params: {
	"weaponName":"Death Star",
	"planetName": "Alderaan"
}

Response: {
    "planetMessage": "Planet took 474 damage and has 99404 shield left.",
    "weaponMessage": "Death Star did 474 damage and left 999 ammo."
}
```

Then this service will decrease ammo of the given weapon and return messages about what damage is done and how much ammo left.
You can see how we decrease the ammo of the weapon below, in **Repositories** section.

### Planet Service:

Planet service will get weapon and planet name as parameters. Then, using **CalculateMeta** helper function, will calculate how much damage will be done.
After getting the damage, service will decrease given planet's shield and return informing message about planet and how much damage is done.

```sh
POST http://localhost:3000/api/planet/Defend

Params: {
    "weaponName": "Death Star",
	"planetName": "Alderaan"
}

Response: {
    "damage": 122,
    "planetMessage": "Planet took 122 damage and has 99878 shield left."
}

```

To get more information about `Moleculer Services`, please visit [Moleculer Documentation](https://moleculer.services/docs/0.13/services.html)

## Repositories

In order to interact with the database, we are using **Repository** pattern. Every **Entity** has a corresponding **Repository**.

For example, in order to fetch **Death Star Weapon** from the database, and make it ready to fire, we should;
```
const deathStar = WeaponRepository.Get('Death Star')
```

When a weapon fires, it loses 1 ammo. We should update the database properly by using repository.

```js
const { remainingAmmo } = await WeaponRepository.DecreaseAmmo('Death Star');
```

If you want to update the shield of the planet;

```ts
const { remainingShield } = await PlanetRepository.UpdateShield('Alderaan', 5000);
```


To get more information about **Repository Pattern** please [visit here](https://deviq.com/repository-pattern/)

## Communication between services

In MoleculerJS we are calling other services with a simple string parameter where service name and method separated by dot.
This is not useful. Since we don't have autocomplete, we need to remember every service and action name to call them.

```
const params = {...}

ctx.call("planet.Defend", params)
```

As the codebase goes bigger, it becomes harder and harder to remember every single service name and their actions.
To fix this, we introduced **ServiceHelpers** to call services. Every service has a helper;
```
export namespace AttackHelper {
	const prefix: string = 'attack';

	export const Fire = async (ctx: Context, params: IAttack.AttackInDto): Promise<IAttack.AttackOutDto> =>
		await ctx.call(`${prefix}.Fire`, params);
}

```

Then we can use it in other services;
```
AttackHelper.Fire(ctx, {...params})
```

If we want to call `planet` service's `Defend` action inside `Attack` service, it's straightforward;

```
const { damage, planetMessage } = await PlanetHelper.Defend(ctx, { weaponName, planetName });
```

As you can see above, it's just invoking a function and getting variables back.


================================================
FILE: documentation/docs/features.md
================================================
---
id: features
title: What's included?
---


moleculerjs-boilerplate project provides a lot of features out of the box. Below is an overview of the included technologies.

* **Moleculer** - Moleculer is a fast, modern and powerful microservices framework for Node.js.
* **Typescript** - Superset of JavaScript which primarily provides optional static typing, classes and interfaces. path support(allias)
* **Built-in Project CLI**- Create service, model, interface and unit-test with one command by using built-in cli.
* **Docker** - A tool designed to make it easier to create, deploy, and run applications by using containers.
* **Eslint** - The pluggable linting utility.
* **Swagger** - A framework backed by a large ecosystem of tools that helps developers design, build, document, and consume RESTful Web services.
* **Jest** - Javascript testing framework , created by developers who created react
* **TypeORM** - TypeORM is specifically an ORM that converts data between JavaScript / TypeScript to a variety of databases.
* **Service Helpers** - Better way to consume services.
* **Seeder** - Easy to integrate, well structured seeder for tests.



================================================
FILE: documentation/docs/getting-started.md
================================================
---
id: getting-started
title: Getting Started
sidebar_label: Getting Started
---

## About Moleculer

Moleculer is a fast, modern and powerful microservices framework for Node.js. It helps you to build efficient, reliable & scalable services. Moleculer provides many features for building and managing your microservices.


### Features of Moleculer
- Promise-based solution (async/await compatible)
- request-reply concept
- support streams
- support event-driven architecture with balancing
- built-in service registry & dynamic service discovery
- load balanced requests & events (round-robin, random, cpu-usage, latency)
- many fault tolerance features (Circuit Breaker, Bulkhead, Retry, Timeout, Fallback)
- supports middlewares
- supports versioned services
- service mixins
- built-in caching solution (memory, Redis)
- pluggable transporters (TCP, NATS, MQTT, Redis, NATS Streaming, Kafka)
- pluggable serializers (JSON, Avro, MsgPack, Protocol Buffers, Thrift)
- pluggable validator
- multiple services on a node/server
- all nodes are equal, no master/leader node
- parameter validation with fastest-validator
- built-in health monitoring & metrics
- official API gateway module and many other modules…

<br>

This boilerplate make it easier to get started with a well-structured Moleculer Microservice.

For more information about [Moleculer](https://moleculer.services) 




================================================
FILE: documentation/docs/setup.md
================================================
---
id: setup
title: Setup
---
To create a new app, you may choose one of the following methods:
#### Clone the repository:

```sh
git clone https://github.com/pankod/moleculerjs-boilerplate.git
```


#### Install the dependencies:


```sh
npm install
```

#### Setup Database (Optional):

We've integrated a microservice example to show how services connect together. We have an example database; you can copy this to play with services.

```sh
npm run setup-db
```

#### Running Microservices:

 ```sh
 npm run dev
 ```

This command will build and run services in the `services` directory. Also it will generate documentation and start swagger UI at port 3001.

#### Running with Docker

```sh
npm run dc:up
```

This should start services independently at port 3000.


================================================
FILE: documentation/docs/structure.md
================================================
---
id: structure
title: Structure
sidebar_label: Structure
---

After the setup is complete, your app should have the following directory structure:

```js
.
├── public
│   ├── banner.png
│   ├── favicon.ico
│   └── index.html
├── services
│   ├── api.service.ts
│   ├── attack.service.ts
│   ├── index.ts
│   └── planet.service.ts
├── src
│   ├── Entities
│   │   ├── Connection.ts
│   │   ├── Planet.ts
│   │   ├── Weapon.ts
│   │   └── index.ts
│   ├── Interfaces
│   │   ├── Meta
│   │   │   ├── DamageMetaOutDto.d.ts
│   │   │   └── index.ts
│   │   ├── Repositories
│   │   │   ├── Planet
│   │   │   │   ├── DecreaseShieldOutDto.d.ts
│   │   │   │   └── index.ts
│   │   │   └── Weapon
│   │   │       ├── DecreaseAmmoOutDto.d.ts
│   │   │       └── index.ts
│   │   ├── Services
│   │   │   ├── Attack
│   │   │   │   ├── IAttack.d.ts
│   │   │   │   └── index.ts
│   │   │   └── Planet
│   │   │       ├── IPlanet.d.ts
│   │   │       └── index.ts
│   │   └── index.ts
│   ├── Meta
│   │   ├── CalculateMeta.ts
│   │   └── index.ts
│   ├── Repositories
│   │   ├── ErrorHelpers.ts
│   │   ├── Planet.ts
│   │   ├── Shared.ts
│   │   ├── Weapon.ts
│   │   └── index.ts
│   └── ServiceHelpers
│       ├── AttackHelper.ts
│       ├── PlanetHelper.ts
│       └── index.ts
├── swagger
│   ├── config.js
│   ├── index.js
│   ├── package.json
│   └── swagger.json
├── test
│   ├── Config
│   │   ├── Connection.ts
│   │   ├── SetupDatabase.ts
│   │   └── mock.setup.ts
│   ├── Integration
│   │   ├── attack.spec.ts
│   │   └── planet.spec.ts
│   ├── Seeder
│   │   ├── AttackSeeder.ts
│   │   ├── PlanetSeeder.ts
│   │   └── index.ts
│   ├── Unit
│   │   ├── Helper
│   │   │   ├── AttackHelper.spec.ts
│   │   │   └── PlanetHelper.spec.ts
│   │   ├── Meta
│   │   │   └── CalculateMeta.spec.ts
│   │   ├── MicroServices
│   │   │   ├── attack.spec.ts
│   │   │   └── planet.spec.ts
│   │   └── Repositories
│   │       ├── ErrorHelpers.spec.ts
│   │       ├── Planet.spec.ts
│   │       └── Weapon.spec.ts
│   └── Utils
│       ├── BrokerHelper.ts
│       ├── DummyContext.ts
│       └── index.ts
├── Dockerfile
├── LICENSE
├── README.md
├── banner.png
├── cli.gif
├── db.sqlite
├── db.sqlite.example
├── docker-compose.env
├── docker-compose.yml
├── moleculer.config.ts
├── moleculerjs-cover.png
├── package-lock.json
├── package.json
├── swaggerConfig.json
├── tsconfig.json
└── tsconfig.production.json
```


================================================
FILE: documentation/docs/swagger.md
================================================
---
id: swagger
title: Usage
sidebar_label: Swagger
---

`swagger-jsdoc` is a library which returns the validated OpenAPI specification as JSON or YAML.

`moleculerjs-boilerplate` uses `swagger-jsdoc` for generating swagger.json file.

This code block shows swagger-jsdoc in **services/attack.service** of example app.

````
	/**
	* @swagger
	*
	*  attack/Fire:
	*    post:
	*      description: Attacks to the planet with given weapon.
	*      produces:
	*        - application/json
	*      consumes:
	*        - application/json
	*      parameters:
	*        - in: body
	*          name: params
	*          schema:
	*            type: object
	*            required:
	*              - weaponName
	*              - planetName
	*            properties:
	*              weaponName:
	*                type: string
	*                default: Death Star
	*              planetName:
	*                type: string
	*      responses:
	*        200:
	*          description: Example attack result
	*        422:
	*          description: Missing parameters
	*/
````
<br>

After running the service you will see the example API documentation on localhost:3001 which is shown at the below.

<br>
<img src="assets/swagger.png" align="center" />
<br>

>Refer to [offical documentation](https://swagger.io/docs/specification/2-0/basic-structure/) for detailed usage. 



================================================
FILE: documentation/docs/testing.md
================================================
---
id: testing
title: Testing
sidebar_label: Testing
---

This boilerplate uses [Jest](https://jestjs.io/docs/en/getting-started) for Unit Testing and [SuperTest](https://github.com/visionmedia/supertest) for integration tests.

## Seeder
We have included seeder to the project. Also we have a helper called `setupDatabase`, you can include this to `beforeEach` block of your tests.
This helper will reset database and seed the database.

Ideally, we are adding this setupDatabase helper to the `beforeEach` block. This will make sure that we run tests against freshly seeded database.

```ts
const setupDatabase = async (): Promise<void> => {
	await CreateConnection();

	await Seeder.seed();
};
```

```ts
beforeEach(async () => {
	await setupDatabase();
});
```


## Examples
### Testing Service Helpers

```js
	describe('Weapon service helpers', () => {
		it('should trigger Fire method', async () => {
			const params: IAttack.AttackInDto = {
				weaponName: 'Death Star',
				planetName: 'Alderaan',
			};

			const result = await AttackHelper.Fire(DummyContext.getCall(params), params);

			expect(result).toBeDefined();
		});
	});
```

### Testing Metas

```js
	it('should calculate remaining shield', async () => {
		const entityManager = getManager();

		const weapon = await entityManager.findOne(Weapon, { name: 'Death Star' });
		const planet = await entityManager.findOne(Planet, { name: 'Alderaan' });

		const { damage, remainingShield } = await CalculateMeta.Damage(weapon, planet);

		expect(remainingShield).toEqual(planet.shield - damage);
	});
```

### Testing Service Methods

```typescript
	const broker = BrokerHelper.setupBroker();

	beforeEach(async () => {
		await broker.start();
		await setupDatabase();
	});

	afterEach(async () => {
		await broker.stop();
	});

	describe('Test attack service', () => {
		const params = {
			planetName: 'Alderaan',
			weaponName: 'Death Star',
		};

		describe('Fire method', async () => {
			it('when ammo is up', async () => {
				const { planetMessage, weaponMessage } = await AttackHelper.Fire(broker as any, params);

				expect(planetMessage).toContain('Planet took');
				expect(weaponMessage).toContain('Death Star did');
			});

			it('when ammo is empty', async () => {
				getManager().update(Weapon, { name: 'Death Star' }, { ammo: 0 });

				const { planetMessage, weaponMessage } = await AttackHelper.Fire(broker as any, params);

				expect(planetMessage).toEqual('Planet took no damage');
				expect(weaponMessage).toEqual('This weapon has no ammo');
			});
		});
	});
```

### Testing Repositories

```typescript
	describe('Planet Repository Methods', () => {
		beforeEach(async () => {
			await setupDatabase();
		});

		afterEach(async () => {
			await getConnection().close();
		});

		describe('Get', () => {
			it('should get planet if there is any', async () => {
				const planetName = 'Alderaan';

				const planet = await PlanetRepository.Get(planetName);

				expect(planet.name).toEqual(planetName);
			});

			it('should raise error', async () => {
				const planetName = 'I dont exist';

				expect(() => PlanetRepository.Get(planetName)).toThrowError;
			});
		});

		it('should update shield', async () => {
			const planetName = 'Alderaan';

			const expectedShield = 1000;

			const { remainingShield } = await PlanetRepository.UpdateShield(planetName, expectedShield);

			expect(remainingShield).toEqual(expectedShield);
		});
	});
```

### Integration Tests For Services

```typescript
	const request = require("supertest");
	const broker = BrokerHelper.setupBroker();
	let server;

	beforeEach(async () => {
		await setupDatabase();
	});

	afterEach(async () => {
		await getConnection().close();
	});

	beforeAll(() => {
		const service = broker.createService(ApiGateway);
		server = service.server;
		return broker.start();
	});

	afterAll(() => broker.stop());

	describe("Test Attack service requests", () => {
		it("Test POST request on attack service Fire method", () => {

			const params = {
				planetName: 'Alderaan',
				weaponName: 'Death Star'
			}

			return request(server)
				.post("/attack/Fire")
				.query({ ...params })
				.then(res => {
					expect(res.statusCode).toBe(200);
					expect(res.headers["content-type"]).toBe("application/json; charset=utf-8");
					expect(res.body.planetMessage).toContain('Planet took');
					expect(res.body.weaponMessage).toContain('Death Star did');
				});
		});
	});

```


================================================
FILE: documentation/docs/typeorm.md
================================================
---
id: typeorm
title: TypeORM & Repository
sidebar_label: TypeORM
---

`createConnection` method in  `src/Entities/Connection` file is responsible for creating database connection. 

Then, `Repositories` handles database interactions with `getManager` method of TypeORM.

Here is a planet Entity example from example app;

```
//#region Global Imports
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
//#endregion Global Imports

@Entity()
export class Planet {
	@PrimaryGeneratedColumn()
	id: number;

	@Column()
	name: string;

	@Column()
	shield: number;
}
```

And this is Planet repository;

```
//#region Global Imports
import { getManager } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import { Planet } from '@Entities/Planet';
import { getResource } from './Shared';
//#endregion Local Imports

//#region Interface Imports
import { DecreaseShieldOutDto } from '@Interfaces';
//#endregion Interface Imports

export namespace PlanetRepository {
	export const Get = async (planetName: string): Promise<Planet> => {
		return await getResource(Planet, { name: planetName });
	};

	export const DecreaseShield = async (
		planetName: string,
		remainingShield: number,
	): Promise<DecreaseShieldOutDto> => {
		const planet = await getResource(Planet, { name: planetName });

		planet.shield = remainingShield;

		await getManager().save(planet);

		return { remainingShield: planet.shield };
	};
}

```

>Refer to [offical documentation](https://typeorm.io/#/entities) for detailed usage. 



================================================
FILE: documentation/website/config.yml
================================================
GIT_USER=docusaurus-bot
USE_SSH=true


================================================
FILE: documentation/website/core/Footer.js
================================================
/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react');

const docs = require("../docs.json");

class Footer extends React.Component {

  constructor() {
    super();
    this.state = {
      docs
    }
  }

  docUrl(doc, language) {
    const baseUrl = this.props.config.baseUrl;
    const docsUrl = this.props.config.docsUrl;
    const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;
    const langPart = `${language ? `${language}/` : ''}`;
    return `${baseUrl}${docsPart}${langPart}${doc}`;
  }

  pageUrl(doc, language) {
    const baseUrl = this.props.config.baseUrl;
    return baseUrl + (language ? `${language}/` : '') + doc;
  }

  render() {
    return (
      <footer className="nav-footer" id="footer">
        <section className="sitemap">
          <a href={this.props.config.baseUrl} className="nav-home">
            {this.props.config.footerIcon && (
              <img
                src={this.props.config.baseUrl + this.props.config.footerIcon}
                alt={this.props.config.title}
                width="66"
              />
            )}
          </a>
          <div>
            <h5>Docs</h5>
            {
              this.state.docs.map((doc, index) => (
                <a key={index} href={this.docUrl(`${doc.id}.html`, this.props.language)}>
                  {doc.title}
                </a>
              ))
            }
          </div>
          <div>
            <h5>Community</h5>
            {
              this.props.config.socialMediaUrl.map((url, index) => (
                <a
                  key={index}
                  href={url.url}
                  target="_blank"
                  rel="noreferrer noopener">
                  {url.title}
                </a>
              ))
            }
          </div>
          <div>
            <h5>More</h5>
            <a href="https://github.com/pankod">GitHub</a>
            <a
              className="github-button"
              href={this.props.config.repoUrl}
              data-icon="octicon-star"
              data-count-href="/facebook/docusaurus/stargazers"
              data-show-count="true"
              data-count-aria-label="# stargazers on GitHub"
              aria-label="Star this project on GitHub">
              Star
            </a>
          </div>
        </section>

        <a
          href="https://github.com/pankod/moleculerjs-boilerplate"
          target="_blank"
          rel="noreferrer noopener"
          className="fbOpenSource">
          <img
            src={`${this.props.config.baseUrl}img/pankod_footer_logo.png`}
            alt="Pankod Open Source"
            width="170"
          />
        </a>
        <section className="copyright">{this.props.config.copyright}</section>
      </footer>
    );
  }
}

module.exports = Footer;


================================================
FILE: documentation/website/docs.json
================================================
[
	{
		"id": "getting-started",
		"title": "Getting Started"
	},
	{
		"id": "example-app",
		"title": "Example App",
		"sidebarLevel": null
	},
	{
		"id": "testing",
		"title": "Features",
		"sidebarLevel": null
	},
	{
		"id": "setup",
		"title": "Setup",
		"sidebarLevel": null
	}
]


================================================
FILE: documentation/website/i18n/en.json
================================================
{
  "_comment": "This file is auto-generated by write-translations.js",
  "localized-strings": {
    "next": "Next",
    "previous": "Previous",
    "tagline": "Moleculer JS Microservice Boilerplate with Typescript, TypeORM, CLI, Service Helpers, Swagger, Jest, Docker, Eslint support and everything you will ever need to deploy rock solid projects.",
    "docs": {
      "cli-migration-guide": {
        "title": "CLI Migrate Guide",
        "sidebar_label": "Migration Guide"
      },
      "cli-overview": {
        "title": "Overview",
        "sidebar_label": "Overview"
      },
      "cli-usage": {
        "title": "Usage",
        "sidebar_label": "Usage"
      },
      "deployment": {
        "title": "Deployment",
        "sidebar_label": "Deployment"
      },
      "eslint": {
        "title": "Usage",
        "sidebar_label": "ESLint"
      },
      "example-app": {
        "title": "Example App",
        "sidebar_label": "Example App"
      },
      "features": {
        "title": "What's included?"
      },
      "getting-started": {
        "title": "Getting Started",
        "sidebar_label": "Getting Started"
      },
      "setup": {
        "title": "Setup"
      },
      "structure": {
        "title": "Structure",
        "sidebar_label": "Structure"
      },
      "swagger": {
        "title": "Usage",
        "sidebar_label": "Swagger"
      },
      "testing": {
        "title": "Testing",
        "sidebar_label": "Testing"
      },
      "typeorm": {
        "title": "TypeORM & Repository",
        "sidebar_label": "TypeORM"
      }
    },
    "links": {
      "Docs": "Docs",
      "Github": "Github"
    },
    "categories": {
      "Introduction": "Introduction",
      "Overview": "Overview",
      "Features": "Features",
      "Project CLI": "Project CLI"
    }
  },
  "pages-strings": {
    "Help Translate|recruit community translators for your project": "Help Translate",
    "Edit this Doc|recruitment message asking to edit the doc source": "Edit",
    "Translate this Doc|recruitment message asking to translate the docs": "Translate"
  }
}


================================================
FILE: documentation/website/package.json
================================================
{
	"scripts": {
		"examples": "docusaurus-examples",
		"start": "docusaurus-start",
		"build": "docusaurus-build",
		"publish-gh-pages": "docusaurus-publish",
		"write-translations": "docusaurus-write-translations",
		"version": "docusaurus-version",
		"rename-version": "docusaurus-rename-version"
	},
	"devDependencies": {
		"docusaurus": "^1.9.0"
	}
}


================================================
FILE: documentation/website/pages/en/help.js
================================================
/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react');

const CompLibrary = require('../../core/CompLibrary.js');

const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;

function Help(props) {
	const { config: siteConfig, language = '' } = props;
	const { baseUrl, docsUrl } = siteConfig;
	const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;
	const langPart = `${language ? `${language}/` : ''}`;
	const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`;

	const supportLinks = [
		{
			content: `Learn more using the [documentation on this site.](${docUrl(
				'doc1.html',
			)})`,
			title: 'Browse Docs',
		},
		{
			content: 'Ask questions about the documentation and project',
			title: 'Join the community',
		},
		{
			content: "Find out what's new with this project",
			title: 'Stay up to date',
		},
	];

	return (
		<div className="docMainWrapper wrapper">
			<Container className="mainContainer documentContainer postContainer">
				<div className="post">
					<header className="postHeader">
						<h1>Need help?</h1>
					</header>
					<p>This project is maintained by a dedicated group of people.</p>
					<GridBlock contents={supportLinks} layout="threeColumn" />
				</div>
			</Container>
		</div>
	);
}

module.exports = Help;


================================================
FILE: documentation/website/pages/en/index.js
================================================
/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react');

const CompLibrary = require('../../core/CompLibrary.js');

const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;

class HomeSplash extends React.Component {
	render() {
		const { siteConfig, language = '' } = this.props;
		const { baseUrl, docsUrl } = siteConfig;
		const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;
		const langPart = `${language ? `${language}/` : ''}`;
		const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`;

		const SplashContainer = props => (
			<div className="homeContainer">
				<div className="homeSplashFade">
					<div className="wrapper homeWrapper">{props.children}</div>
				</div>
			</div>
		);

		const ProjectTitle = () => (
			<h2 className="projectTitle">
				{siteConfig.headerTitle}
				<small className="header-title" >{siteConfig.tagline}</small>
			</h2>
		);

		const PromoSection = props => (
			<div className="section promoSection">
				<div className="promoRow">
					<div className="pluginRowBlock">{props.children}</div>
				</div>
			</div>
		);

		const Button = props => (
			<div className="pluginWrapper buttonWrapper">
				<a className="button" href={props.href} target={props.target}>
					{props.children}
				</a>
			</div>
		);

		return (
			<SplashContainer>
				<div className="inner">
					<img className="home-banner" src="img/banner4.png" />
					<ProjectTitle siteConfig={siteConfig} />

				</div>
				<div className="top-badges">
					<a href="https://codeclimate.com/github/pankod/moleculerjs-boilerplate/maintainability">
						<img src="https://api.codeclimate.com/v1/badges/077c02d5cb9ec7d8a654/maintainability" />
					</a>
					<a href="https://codeclimate.com/github/pankod/moleculerjs-boilerplate/test_coverage">
						<img src="https://api.codeclimate.com/v1/badges/077c02d5cb9ec7d8a654/test_coverage" />
					</a>
					<a href="https://travis-ci.org/pankod/moleculerjs-boilerplate">
						<img src="https://travis-ci.org/pankod/moleculerjs-boilerplate.svg?branch=master" alt="Build Status" />
					</a>
					<a href="https://david-dm.org/pankod/moleculerjs-boilerplate">
						<img src="https://david-dm.org/pankod/moleculerjs-boilerplate.svg" alt="Dependency Status" />
					</a>
					<a href="https://david-dm.org/pankod/moleculerjs-boilerplate#info=devDependencies">
						<img src="https://david-dm.org/pankod/moleculerjs-boilerplate/dev-status.svg" alt="devDependency Status" />
					</a>
				</div>
			</SplashContainer>
		);
	}
}

class Index extends React.Component {
	render() {
		const { config: siteConfig, language = '' } = this.props;
		const { baseUrl } = siteConfig;

		const Block = props => (
			<Container
				padding={['bottom', 'top']}
				id={props.id}
				background={props.background}>
				<GridBlock
					align={props.align}
					contents={props.children}
					layout={props.layout}
				/>
			</Container>
		);

		const FeatureCallout = () => (
			<div
				className="productShowcaseSection paddingBottom"
				style={{ textAlign: 'center' }}>
				<h2>Features </h2>
			</div>
		);

		const TryOut = () => (
			<Block id="try">
				{[
					{
						content:
							'Jest is a testing tool from Facebook that makes it easy to perform unit testing in JavaScript.',
						image: `${baseUrl}img/testing.png`,
						imageAlign: 'left',
						title: 'Jest',
					},
				]}
			</Block>
		);

		const LearnHow = () => (
			<Block background="light">
				{[
					{
						content:
							'Pankod boilerplate is shipped with a CLI tool to streamline the creation of new components.',
						image: `${baseUrl}img/cli.gif`,
						imageAlign: 'right',
						title: 'Built-in Project CLI',
					},
				]}
			</Block>
		);
		const LastFeature = () => (
			<Block background="light">
				{[
					{
						content: 'Provides easy communication contract between services.',
						image: `${baseUrl}img/service-helpers.png`,
						imageAlign: 'right',
						title: 'Service Helpers'
					},
				]}
			</Block>
		);

		const Features = () => (
			<React.Fragment>
				<Block layout="fourColumn" align='center'>
					{[
						{
							content: 'Progressive microservices framework for Node.js.',
							image: `${baseUrl}img/moleculer-logo2.png`,
							imageAlign: 'top',
							title: 'Moleculer',
						},
						{
							content: 'Superset of JavaScript which primarily provides optional static typing, classes and interfaces.',
							image: `${baseUrl}img/typescript-logo.png`,
							imageAlign: 'top',
							title: 'TypeScript',
						},
						{
							content: 'TypeORM is specifically an ORM that converts data between JavaScript / TypeScript to a variety of databases',
							image: `${baseUrl}img/typeorm.png`,
							imageAlign: 'top',
							title: 'TypeORM',
							className: 'orm'
						},
						{
							content: 'Create services, models and interfaces with one command by using built-in cli.',
							image: `${baseUrl}img/cli-logo.png`,
							imageAlign: 'top',
							title: 'Project CLI',
						}



					]}
				</Block>

				<Block layout="fourColumn" align='center'>
					{[

						{
							content: 'Jest is a testing tool from Facebook that makes it easy to perform unit testing in JavaScript.',
							image: `${baseUrl}img/jest-logo.png`,
							imageAlign: 'top',
							title: 'Jest',
						},
						{
							content: 'Create, deploy, and run applications by using docker containers.',
							image: `${baseUrl}img/docker2.png`,
							imageAlign: 'top',
							title: 'Docker',
						},
						{
							content: 'Tools that helps developers design, build, document, and consume RESTful Web services.',
							image: `${baseUrl}img/swagger.png`,
							imageAlign: 'top',
							title: 'Swagger',
						},
						{
							content: 'Linter for the JavaScript programming language.',
							image: `${baseUrl}img/eslint-logo.png`,
							imageAlign: 'top',
							title: 'Eslint',
						}
					]}
				</Block>
			</React.Fragment>
		);



		return (
			<div>
				<HomeSplash siteConfig={siteConfig} language={language} />
				<div className="mainContainer homeMain">
					<Features />
					<FeatureCallout />
					<LearnHow />
					<TryOut />
					<LastFeature />
				</div>
			</div>
		);
	}
}

module.exports = Index;


================================================
FILE: documentation/website/pages/en/users.js
================================================
/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react');

const CompLibrary = require('../../core/CompLibrary.js');

const Container = CompLibrary.Container;

class Users extends React.Component {
	render() {
		const { config: siteConfig } = this.props;
		if ((siteConfig.users || []).length === 0) {
			return null;
		}

		const editUrl = `${siteConfig.repoUrl}/edit/master/website/siteConfig.js`;
		const showcase = siteConfig.users.map(user => (
			<a href={user.infoLink} key={user.infoLink}>
				<img src={user.image} alt={user.caption} title={user.caption} />
			</a>
		));

		return (
			<div className="mainContainer">
				<Container padding={['bottom', 'top']}>
					<div className="showcaseSection">
						<div className="prose">
							<h1>Who is Using This?</h1>
							<p>This project is used by many folks</p>
						</div>
						<div className="logos">{showcase}</div>
						<p>Are you using this project?</p>
						<a href={editUrl} className="button">
							Add your company
            </a>
					</div>
				</Container>
			</div>
		);
	}
}

module.exports = Users;


================================================
FILE: documentation/website/sidebars.json
================================================
{
	"docs": {
		"Introduction": [
			"getting-started",
			"features"
		],
		"Overview": [
			"setup",
			"example-app",
			"structure",
			"deployment"
		],
		"Features": [
			"testing",
			"swagger",
			"eslint",
			"typeorm"
		],
		"Project CLI": [
			"cli-overview",
			"cli-usage",
			"cli-migration-guide"
		]
	}
}


================================================
FILE: documentation/website/siteConfig.js
================================================
/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// See https://docusaurus.io/docs/site-config for all the possible
// site configuration options.

// List of projects/orgs using your project for the users page.
const users = [
	{
		caption: 'User1',
		// You will need to prepend the image path with your baseUrl
		// if it is not '/', like: '/test-site/img/image.jpg'.
		image: '/img/undraw_open_source.svg',
		infoLink: 'https://www.facebook.com',
		pinned: true,
	},
];

const organizationName = 'pankod';
const projectName = 'moleculerjs-boilerplate';
const packageName = 'moleculerjs-boilerplate';
const url = [
	{
		title: 'Twitter',
		url: 'https://twitter.com/PankodDev',
	},
];

const siteConfig = {
	title: 'Pankod', // Title for your website.
	headerTitle: 'moleculerjs-boilerplate',
	tagline:
		'Moleculer JS Microservice Boilerplate with Typescript, TypeORM, CLI, Service Helpers, Swagger, Jest, Docker, Eslint support and everything you will ever need to deploy rock solid projects.',
	url: 'https://pankod.github.io', // Your website URL
	baseUrl: '/moleculerjs-boilerplate/', // Base URL for your project */
	// For github.io type URLs, you would set the url and baseUrl like:
	//   url: 'https://facebook.github.io',
	//   baseUrl: '/test-site/',

	socialMediaUrl: url,
	packageName: packageName,

	// Used for publishing and more
	projectName: projectName,
	organizationName: organizationName,
	// For top-level user or org sites, the organization is still the same.
	// e.g., for the https://JoelMarcey.github.io site, it would be set like...
	//   organizationName: 'JoelMarcey'

	// For no header links in the top nav bar -> headerLinks: [],
	headerLinks: [
		{ doc: 'getting-started', label: 'Docs' },
		/* 		{ page: 'users', label: 'Help' }, */
		{ href: 'https://github.com/pankod/' + packageName, label: 'Github' },
		{ search: true },
		{ languages: true },
	],

	// If you have users set above, you add it here:
	users,

	/* path to images for header/footer */
	headerIcon: 'img/footer_icon.png',
	footerIcon: 'img/footer_icon.png',
	favicon: 'img/favicon.png',

	/* Colors for website */
	colors: {
		primaryColor: '#2C3E50',
		secondaryColor: '#83878D',
	},

	/* Custom fonts for website */
	/*
	fonts: {
	  myFont: [
		"Times New Roman",
		"Serif"
	  ],
	  myOtherFont: [
		"-apple-system",
		"system-ui"
	  ]
	},
	*/

	// This copyright info is used in /core/Footer.js and blog RSS/Atom feeds.
	copyright: `Copyright © ${new Date().getFullYear()} ${organizationName}`,

	highlight: {
		// Highlight.js theme to use for syntax highlighting in code blocks.
		theme: 'tomorrow-night',
	},

	// Add custom scripts here that would be placed in <script> tags.
	scripts: ['https://buttons.github.io/buttons.js'],

	// On page navigation for the current documentation page.
	onPageNav: 'separate',
	// No .html extensions for paths.
	cleanUrl: true,

	// Open Graph and Twitter card images.
	// Google Analytics id
	gaTrackingId: 'UA-143750629-1',

	// Facebook settings
	facebookAppId: '',
	facebookPixelId: '',
	facebookComments: false,

	// Twitter settings
	twitter: '',
	ogImage: 'img/undraw_online.svg',
	twitterImage: 'img/undraw_tweetstorm.svg',

	// Show documentation's last contributor's name.
	// enableUpdateBy: true,

	// Show documentation's last update time.
	// enableUpdateTime: true,

	// You may provide arbitrary config keys to be used as needed by your
	// template. For example, if you need your repo's URL...
	repoUrl: 'https://github.com/pankod/' + packageName,

	// Custom css
	separateCss: [],
};

module.exports = siteConfig;


================================================
FILE: documentation/website/static/css/custom.css
================================================
/* your custom css */
.nav-footer {
	background-color: #2c3e50;
}

.gridBlock {
	align-items: baseline;
}
.top-badges {
	margin-top: 20px;
}
.top-badges > a {
	margin: 0 2px;
}
.promoSection {
	margin-top: 50px;
}
.home-banner {
	margin-bottom: 50px;
	margin-top: 30px;
}

.homeMain{
	padding-top: 0 !important;
	padding-bottom: 0 !important;
}
.blockImage{
	width: 15%;
}
.projectTitle > small{
	font-size: 42%;
	color:#696969;
	line-height: 1.4;

}

@media only screen and (min-device-width: 360px) and (max-device-width: 736px) {
}

@media only screen and (min-width: 1024px) {
}

@media only screen and (max-width: 1023px) {
}

@media only screen and (min-width: 1400px) {
}

@media only screen and (min-width: 1500px) {
}


================================================
FILE: moleculer.config.ts
================================================
'use strict';
import { BrokerOptions } from 'moleculer';
import 'reflect-metadata';
import * as Moleculer from 'moleculer';
import MoleculerRetryableError = Moleculer.Errors.MoleculerRetryableError;

/**
 * Moleculer ServiceBroker configuration file
 *
 * More info about options: https://moleculer.services/docs/0.14/broker.html#Broker-options
 *
 * Overwrite options in production:
 * ================================
 * 	You can overwrite any option with environment variables.
 * 	For example to overwrite the "logLevel", use `LOGGER=warn` env var.
 * 	To overwrite a nested parameter, e.g. retryPolicy.retries, use `RETRYPOLICY_RETRIES=10` env var.
 *
 * 	To overwrite broker’s deeply nested default options, which are not presented in "moleculer.config.ts",
 * 	via environment variables, use the `MOL_` prefix and double underscore `__` for nested properties in .env file.
 * 	For example, to set the cacher prefix to `MYCACHE`, you should declare an env var as `MOL_CACHER__OPTIONS__PREFIX=MYCACHE`.
 */
const brokerConfig: BrokerOptions = {
	// Namespace of nodes to segment your nodes on the same network.
	namespace: '',
	// Unique node identifier. Must be unique in a namespace.
	nodeID: undefined,

	// Enable/disable logging or use custom logger. More info: https://moleculer.services/docs/0.14/logging.html
	logger: true,
	// Log level for built-in console logger. Available values: trace, debug, info, warn, error, fatal
	logLevel: 'info',
	// Log formatter for built-in console logger. Available values: default, simple, short. It can be also a `Function`.
	logFormatter: 'default',
	// Custom object & array printer for built-in console logger.
	logObjectPrinter: undefined,

	// Define transporter.
	// More info: https://moleculer.services/docs/0.14/networking.html
	transporter: {
		type: 'TCP',
		options: {
			udpDiscovery: false,
		},
	},

	// Define a serializer.
	// Available values: "JSON", "Avro", "ProtoBuf", "MsgPack", "Notepack", "Thrift".
	// More info: https://moleculer.services/docs/0.14/networking.html
	serializer: 'JSON',

	// Number of milliseconds to wait before reject a request with a RequestTimeout error. Disabled: 0
	requestTimeout: 10 * 1000,

	// Retry policy settings. More info: https://moleculer.services/docs/0.14/fault-tolerance.html#Retry
	retryPolicy: {
		// Enable feature
		enabled: false,
		// Count of retries
		retries: 5,
		// First delay in milliseconds.
		delay: 100,
		// Maximum delay in milliseconds.
		maxDelay: 1000,
		// Backoff factor for delay. 2 means exponential backoff.
		factor: 2,
		// A function to check failed requests.
		check: (err: Error) => err && err instanceof MoleculerRetryableError && !!err.retryable,
	},

	// Limit of calling level. If it reaches the limit, broker will throw an MaxCallLevelError error. (Infinite loop protection)
	maxCallLevel: 100,

	// Number of seconds to send heartbeat packet to other nodes.
	heartbeatInterval: 5,
	// Number of seconds to wait before setting node to unavailable status.
	heartbeatTimeout: 15,

	// Tracking requests and waiting for running requests before shutdowning. More info: https://moleculer.services/docs/0.14/fault-tolerance.html
	tracking: {
		// Enable feature
		enabled: false,
		// Number of milliseconds to wait before shutdowning the process
		shutdownTimeout: 5000,
	},

	// Disable built-in request & emit balancer. (Transporter must support it, as well.)
	disableBalancer: false,

	// Settings of Service Registry. More info: https://moleculer.services/docs/0.14/registry.html
	registry: {
		// Define balancing strategy.
		// Available values: "RoundRobin", "Random", "CpuUsage", "Latency"
		strategy: 'RoundRobin',
		// Enable local action call preferring.
		preferLocal: true,
	},

	// Settings of Circuit Breaker. More info: https://moleculer.services/docs/0.14/fault-tolerance.html#Circuit-Breaker
	circuitBreaker: {
		// Enable feature
		enabled: false,
		// Threshold value. 0.5 means that 50% should be failed for tripping.
		threshold: 0.5,
		// Minimum request count. Below it, CB does not trip.
		minRequestCount: 20,
		// Number of seconds for time window.
		windowTime: 60,
		// Number of milliseconds to switch from open to half-open state
		halfOpenTime: 10 * 1000,
		// A function to check failed requests.
		check: (err: Error) => err && err instanceof MoleculerRetryableError && err.code >= 500,
	},

	// Settings of bulkhead feature. More info: https://moleculer.services/docs/0.14/fault-tolerance.html#Bulkhead
	bulkhead: {
		// Enable feature.
		enabled: false,
		// Maximum concurrent executions.
		concurrency: 10,
		// Maximum size of queue
		maxQueueSize: 100,
	},

	// Enable parameters validation. More info: https://moleculer.services/docs/0.13/validating.html
	validator: true,

	// Enable metrics function. More info: https://moleculer.services/docs/0.14/metrics.html
	metrics: {
		enabled: true,
	},

	// Register internal services ("$node"). More info: https://moleculer.services/docs/0.14/services.html#Internal-services
	internalServices: true,
	// Register internal middlewares. More info: https://moleculer.services/docs/0.14/middlewares.html#Internal-middlewares
	internalMiddlewares: true,

	// Watch the loaded services and hot reload if they changed. You can also enable it in Moleculer Runner with `--hot` argument
	hotReload: false,

	// Register custom middlewares
	middlewares: [],

	// Called after broker created.
	// eslint-disable-next-line @typescript-eslint/no-unused-vars
	created(broker) {},

	// Called after broker starte.
	// eslint-disable-next-line @typescript-eslint/no-unused-vars
	started(broker) {},

	// Called after broker stopped.
	// eslint-disable-next-line @typescript-eslint/no-unused-vars
	stopped(broker) {},

	// Register custom REPL commands.
	replCommands: undefined,
};

export = brokerConfig;

================================================
FILE: package.json
================================================
{
  "name": "moleculerjs-boilerplate",
  "version": "1.0.0",
  "description": "My Moleculer microservices project",
  "scripts": {
    "build": "tsc",
    "dev": "ts-node -r tsconfig-paths/register ./node_modules/moleculer/bin/moleculer-runner.js --hot --repl --config moleculer.config.ts services/**/*.service.ts & npm run swagger",
    "start": "TS_NODE_PROJECT=tsconfig.production.json node -r tsconfig-paths/register ./node_modules/moleculer/bin/moleculer-runner.js dist/services",
    "cli": "pankod-cli add",
    "test": "jest --coverage --runInBand",
    "lint": "eslint -c .eslintrc.js --ext .ts {services,src,test}/**",
    "format": "eslint -c .eslintrc.js --ext .ts --fix {services,src,test}/**",
    "dc:up": "docker-compose up --build -d",
    "dc:down": "docker-compose down",
    "swagger": "swagger-jsdoc -d swagger/config.js -o swagger/swagger.json services/*.service.ts && node ./swagger/index.js",
    "setup-db": "cp db.sqlite.example db.sqlite"
  },
  "pankod": {
    "project": "moleculer"
  },
  "keywords": [
    "microservices",
    "moleculer",
    "typescript",
    "typeorm",
    "swagger",
    "eslint",
    "jest",
    "supertest"
  ],
  "author": "Pankod <info@pankod.com>",
  "devDependencies": {
    "@pankod/pankod-cli": "^0.2.3",
    "@types/jest": "^23.1.1",
    "@types/node": "^10.12.12",
    "@types/supertest": "^2.0.8",
    "@typescript-eslint/eslint-plugin": "^1.9.0",
    "@typescript-eslint/parser": "^1.9.0",
    "eslint": "^5.16.0",
    "eslint-config-prettier": "^4.3.0",
    "eslint-plugin-prettier": "^3.1.0",
    "jest": "^23.6.0",
    "jest-cli": "^23.6.0",
    "moleculer-repl": "^0.5.3",
    "prettier": "^1.17.1",
    "supertest": "^4.0.2",
    "swagger-ui-express": "^4.0.2",
    "ts-jest": "^23.10.5",
    "ts-node": "^7.0.1",
    "typescript": "^3.3.3333"
  },
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.16.4",
    "moleculer": "^0.14.5",
    "moleculer-decorators": "^1.2.0",
    "moleculer-web": "^0.8.0",
    "nats": "^1.3.0",
    "reflect-metadata": "^0.1.13",
    "sqlite3": "^4.1.1",
    "swagger-jsdoc": "^3.2.9",
    "tsconfig-paths": "^3.8.0",
    "typeorm": "^0.2.18"
  },
  "engines": {
    "node": ">= 8.x.x"
  },
  "jest": {
    "coverageDirectory": "<rootDir>/coverage",
    "testEnvironment": "node",
    "moduleFileExtensions": [
      "ts",
      "js"
    ],
    "moduleNameMapper": {
      "^@(Test)(.*)$": "<rootDir>/test/$2",
      "@Entities/Connection": "<rootDir>/test/Config/Connection",
      "^@([A-Z].*)$": "<rootDir>/src/$1"
    },
    "transform": {
      "^.+\\.(ts)$": "ts-jest"
    },
    "testMatch": [
      "**/*.spec.(ts)"
    ],
    "setupTestFrameworkScriptFile": "<rootDir>/test/Config/mock.setup.ts",
    "globals": {
      "ts-jest": {
        "tsConfig": "<rootDir>/tsconfig.json"
      }
    }
  }
}


================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<title>MoleculerJS Boilerplate | Pankod</title>
		<style>
			body {
				width: 100%;
				height: 100%;
				background: #000;
				overflow: hidden;
			}

			.fade {
				position: relative;
				width: 100%;
				min-height: 60vh;
				top: -25px;
				background-image: linear-gradient(0deg, transparent, black 75%);
				z-index: 1;
			}

			.star-wars {
				display: flex;
				justify-content: center;
				position: relative;
				height: 800px;
				color: #feda4a;
				font-family: 'Pathway Gothic One', sans-serif;
				font-size: 500%;
				font-weight: 600;
				letter-spacing: 6px;
				line-height: 150%;
				perspective: 500px;
				text-align: justify;
			}

			.crawl {
				position: relative;
				top: 99999px;
				transform-origin: 50% 100%;
				animation: crawl 60s linear;
			}

			.crawl > .title {
				font-size: 90%;
				text-align: center;
			}

			.crawl > .title h2 {
				margin: 0 0 100px;
				text-transform: uppercase;
			}

			@keyframes crawl {
				0% {
					top: -100px;
					transform: rotateX(20deg) translateZ(0);
				}
				100% {
					top: -6000px;
					transform: rotateX(25deg) translateZ(-2500px);
				}
			}
		</style>
	</head>
	<body>
		<div class="fade"></div>

		<section class="star-wars">
			<div class="crawl">
				<div class="title">
					<h2>MoleculerJS Boilerplate</h2>
					<p>Pankod Open Source</p>
				</div>

				<p>
					MoleculerJS Microservice Boilerplate with Typescript, TypeORM, CLI, Service
					Helpers, Swagger, Jest, Docker, Eslint support and everything you will ever need
					to deploy rock solid projects...
				</p>
				<p>
					A microservice is a single self-contained unit which, together with many others,
					makes up a large application. By splitting your app into small units every part
					of it is independently deployable and scalable, can be written by different
					teams and in different programming languages and can be tested individually.
				</p>
				<p>
					Moleculer is a fast, modern and powerful microservices framework for Node.js. It
					helps you to build efficient, reliable & scalable services. This boilerplate
					make it easier to get started with a well-structured Node.js microservices with
					Typescript.
				</p>
				<p>
					MoleculerJS boilerplate is shipped with a CLI tool to streamline the creation of
					new microservices and entities. By using the CLI tool, you may easily add
					entities, services to your project and have all the required interfaces and
					imports are automatically created for you.
				</p>
			</div>
		</section>
	</body>
</html>


================================================
FILE: services/api.service.ts
================================================
//#region Global Imports
import { ServiceSchema } from 'moleculer';
import ApiGateway = require('moleculer-web');
//#endregion Global Imports

const ApiService: ServiceSchema = {
	name: 'api',

	mixins: [ApiGateway],

	// More info about settings: https://moleculer.services/docs/0.13/moleculer-web.html
	settings: {
		port: process.env.PORT || 3000,

		routes: [
			{
				aliases: {},
				cors: {
					credentials: true,
					methods: ['GET', 'OPTIONS', 'POST'],
					origin: ['*'],
				},
				path: '/api',
			},
		],

		// Serve assets from 'public' folder
		assets: {
			folder: 'public',
		},
	},
};

export = ApiService;


================================================
FILE: services/attack.service.ts
================================================
//#region Global Imports
import { Context, Service as MoleculerService } from 'moleculer';
import { Action, Method, Service } from 'moleculer-decorators';
import { getConnection } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import { WeaponRepository } from '@Repositories';
import { PlanetHelper } from '@ServiceHelpers';
import connectionInstance from '@Entities/Connection';

//#endregion Local Imports

//#region Interface Imports
import { IAttack } from '@Interfaces';
//#endregion Interface Imports

@Service({
	name: 'attack',
})
class AttackService extends MoleculerService {
	public async started() {
		return await connectionInstance();
	}

	@Action({
		params: {
			weaponName: { type: 'string', min: 2 },
			planetName: { type: 'string', min: 2 },
		},
	})
	public async Fire(ctx: Context<IAttack.FireInDto>): Promise<IAttack.FireOutDto> {
		const response = await this.FireMethod(ctx);

		return response;
	}

	@Method
	/**
	 * @swagger
	 *
	 *  /attack/Fire:
	 *    post:
	 *      description: Attacks to the planet with given weapon.
	 *      produces:
	 *        - application/json
	 *      consumes:
	 *        - application/json
	 *      parameters:
	 *        - in: body
	 *          name: params
	 *          schema:
	 *            type: object
	 *            required:
	 *              - weaponName
	 *              - planetName
	 *            properties:
	 *              weaponName:
	 *                type: string
	 *                example: Death Star
	 *              planetName:
	 *                type: string
	 *                example: Alderaan
	 *      responses:
	 *        200:
	 *          description: Example attack result
	 *        422:
	 *          description: Missing parameters
	 */
	public async FireMethod(ctx: Context<IAttack.FireInDto>): Promise<IAttack.FireOutDto> {
		const { planetName, weaponName } = ctx.params;

		const weapon = await WeaponRepository.Get(weaponName);

		if (weapon.ammo <= 0) {
			return {
				planetMessage: 'Planet took no damage',
				weaponMessage: 'This weapon has no ammo',
			};
		}

		const { remainingAmmo } = await WeaponRepository.DecreaseAmmo(weaponName);

		const { damage, planetMessage } = await PlanetHelper.Defend(ctx, {
			weaponName,
			planetName,
		});

		const weaponMessage = `${weapon.name} did ${damage} damage and left ${remainingAmmo} ammo.`;

		return {
			planetMessage,
			weaponMessage,
		};
	}
	public async stopped() {
		return await getConnection().close();
	}
}

module.exports = AttackService;


================================================
FILE: services/index.ts
================================================
export { AttackService } from './attack.service';
export { PlanetService } from './planet.service';


================================================
FILE: services/planet.service.ts
================================================
//#region Global Imports
import { Context, Service as MoleculerService } from 'moleculer';
import { Action, Method, Service } from 'moleculer-decorators';
import { getConnection } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import { PlanetRepository, WeaponRepository } from '@Repositories';
import { CalculateMeta } from '@Meta';
import { Planet, Weapon } from '@Entities';
import connectionInstance from '@Entities/Connection';
//#endregion Local Imports

//#region Interface Imports
import { IPlanet } from '@Interfaces';
//#endregion Interface Imports

@Service({
	name: 'planet',
})
class PlanetService extends MoleculerService {
	public async started() {
		return await connectionInstance();
	}

	@Action({
		params: {
			weaponName: { type: 'string', min: 2 },
			planetName: { type: 'string', min: 2 },
		},
	})
	public async Defend(ctx: Context<IPlanet.DefendInDto>): Promise<IPlanet.DefendOutDto> {
		const response = await this.DefendMethod(ctx);

		return response;
	}

	@Method
	/**
	 * @swagger
	 *
	 *  /planet/Defend:
	 *    post:
	 *      description: Attacks to the planet with given weapon.
	 *      produces:
	 *        - application/json
	 *      consumes:
	 *        - application/json
	 *      parameters:
	 *        - in: body
	 *          name: params
	 *          schema:
	 *            type: object
	 *            required:
	 *              - weaponName
	 *              - planetName
	 *            properties:
	 *              weaponName:
	 *                type: string
	 *                example: Death Star
	 *              planetName:
	 *                type: string
	 *                example: Alderaan
	 *      responses:
	 *        200:
	 *          description: Example attack result
	 *        422:
	 *          description: Missing parameters
	 */
	public async DefendMethod(ctx: Context<IPlanet.DefendInDto>): Promise<IPlanet.DefendOutDto> {
		const { planetName, weaponName } = ctx.params;

		const planet: Planet = await PlanetRepository.Get(planetName);
		const weapon: Weapon = await WeaponRepository.Get(weaponName);

		const { damage, remainingShield } = await CalculateMeta.Damage(weapon, planet);

		await PlanetRepository.DecreaseShield(planetName, remainingShield);

		let message;

		if (remainingShield > 0) {
			message = `Planet took ${damage} damage and has ${remainingShield} shield left.`;
		} else {
			message = 'Planet shield ruined! war is lost!';
		}

		return { damage, planetMessage: message };
	}

	public async stopped() {
		return await getConnection().close();
	}
}

module.exports = PlanetService;


================================================
FILE: src/Entities/Connection.ts
================================================
//#region Global Imports
import { createConnection, Connection } from 'typeorm';
//#endregion Global Imports

export default async (): Promise<Connection | undefined> => {
	try {
		return await createConnection({
			type: 'sqlite',
			name: 'default',
			database: './db.sqlite',
			entities: [__dirname + '/*'],
			synchronize: true,
		});
	} catch (error) {
		return undefined;
	}
};


================================================
FILE: src/Entities/Planet.ts
================================================
//#region Global Imports
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
//#endregion Global Imports

@Entity()
export class Planet {
	@PrimaryGeneratedColumn()
	id?: number;

	@Column()
	name: string;

	@Column()
	shield: number;

	constructor(name: string, shield: number) {
		this.name = name;
		this.shield = shield;
	}
}


================================================
FILE: src/Entities/Weapon.ts
================================================
//#region Global Imports
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
//#endregion Global Imports

@Entity()
export class Weapon {
	@PrimaryGeneratedColumn()
	id?: number;

	@Column()
	name: string;

	@Column()
	damage: number;

	@Column()
	ammo: number;

	constructor(name: string, damage: number, ammo: number) {
		this.name = name;
		this.damage = damage;
		this.ammo = ammo;
	}
}


================================================
FILE: src/Entities/index.ts
================================================
export { Planet } from './Planet';
export { Weapon } from './Weapon';


================================================
FILE: src/Interfaces/Meta/DamageMetaOutDto.d.ts
================================================
export interface DamageMetaOutDto {
	damage: number;
	remainingShield: number;
}


================================================
FILE: src/Interfaces/Meta/index.ts
================================================
export { DamageMetaOutDto } from './DamageMetaOutDto';


================================================
FILE: src/Interfaces/Repositories/Planet/DecreaseShieldOutDto.d.ts
================================================
export interface DecreaseShieldOutDto {
	remainingShield: number;
}


================================================
FILE: src/Interfaces/Repositories/Planet/index.ts
================================================
export { DecreaseShieldOutDto } from './DecreaseShieldOutDto';


================================================
FILE: src/Interfaces/Repositories/Weapon/DecreaseAmmoOutDto.d.ts
================================================
export interface DecreaseAmmoOutDto {
	remainingAmmo: number;
}


================================================
FILE: src/Interfaces/Repositories/Weapon/index.ts
================================================
export { DecreaseAmmoOutDto } from './DecreaseAmmoOutDto';


================================================
FILE: src/Interfaces/Services/Attack/IAttack.d.ts
================================================
export namespace IAttack {
	export interface FireInDto {
		planetName: string;
		weaponName: string;
	}

	export interface FireOutDto {
		planetMessage: string;
		weaponMessage: string;
	}
}


================================================
FILE: src/Interfaces/Services/Attack/index.ts
================================================
export { IAttack } from './IAttack';


================================================
FILE: src/Interfaces/Services/Planet/IPlanet.d.ts
================================================
export namespace IPlanet {
	export interface DefendInDto {
		planetName: string;
		weaponName: string;
	}

	export interface DefendOutDto {
		damage: number;
		planetMessage: string;
	}
}


================================================
FILE: src/Interfaces/Services/Planet/index.ts
================================================
export { IPlanet } from './IPlanet';


================================================
FILE: src/Interfaces/index.ts
================================================
export * from '@Interfaces/Meta';
export * from '@Interfaces/Repositories/Planet';
export * from '@Interfaces/Repositories/Weapon';
export * from '@Interfaces/Services/Attack';
export * from '@Interfaces/Services/Planet';


================================================
FILE: src/Meta/CalculateMeta.ts
================================================
//#endregion Local Imports
import { Planet, Weapon } from '@Entities';
//#endregion Local Imports

//#region Interface Imports
import { DamageMetaOutDto } from '@Interfaces';
//#endregion Interface Imports

export namespace CalculateMeta {
	export const Damage = async (weapon: Weapon, planet: Planet): Promise<DamageMetaOutDto> => {
		const { damage: weaponDamage } = weapon;
		const { shield } = planet;

		const damage = Math.floor(Math.random() * weaponDamage);

		const remainingShield = shield - damage;

		return { damage, remainingShield };
	};
}


================================================
FILE: src/Meta/index.ts
================================================
export { CalculateMeta } from '@Meta/CalculateMeta';


================================================
FILE: src/Repositories/ErrorHelpers.ts
================================================
//#region Global Imports
import { Errors } from 'moleculer';
//#endregion Global Imports

export const Throw404 = <R extends {}>(resource: R | undefined, message: string): R => {
	if (!resource) {
		throw new Errors.MoleculerError(message, 404, 'Not Found');
	}
	return resource;
};


================================================
FILE: src/Repositories/Planet.ts
================================================
//#region Global Imports
import { getManager } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import { Planet } from '@Entities/Planet';
import { getResource } from './Shared';
//#endregion Local Imports

//#region Interface Imports
import { DecreaseShieldOutDto } from '@Interfaces';
//#endregion Interface Imports

export namespace PlanetRepository {
	export const Get = async (planetName: string): Promise<Planet> => {
		return await getResource(Planet, { where: { name: planetName } });
	};

	export const DecreaseShield = async (
		planetName: string,
		remainingShield: number,
	): Promise<DecreaseShieldOutDto> => {
		const planet = await getResource(Planet, { where: { name: planetName } });

		planet.shield = remainingShield;

		await getManager().save(planet);

		return { remainingShield: planet.shield };
	};
}


================================================
FILE: src/Repositories/Shared.ts
================================================
//#region Global Imports
import { getManager, ObjectType } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import { Throw404 } from './ErrorHelpers';
//#endregion Local Imports

export const getResource = async <E extends {}>(
	entityClass: ObjectType<E>,
	options: {},
): Promise<E> => {
	const resource = await getManager().findOne(entityClass, options);

	Throw404(resource, `Resource can't be found with options: ${JSON.stringify(options)}`);

	return resource as E;
};


================================================
FILE: src/Repositories/Weapon.ts
================================================
//#region Global Imports
import { getManager } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import { Weapon } from '@Entities/Weapon';
import { getResource } from './Shared';
//#endregion Local Imports

//#region Interfaces Imports
import { DecreaseAmmoOutDto } from '@Interfaces';
//#endregion Interfaces Imports

export namespace WeaponRepository {
	export const Get = async (weaponName: string): Promise<Weapon> => {
		return await getResource(Weapon, { where: { name: weaponName } });
	};

	export const DecreaseAmmo = async (weaponName: string): Promise<DecreaseAmmoOutDto> => {
		const weapon = await getResource(Weapon, { where: { name: weaponName } });

		weapon.ammo = weapon.ammo - 1;

		getManager().save(weapon);

		return { remainingAmmo: weapon.ammo };
	};
}


================================================
FILE: src/Repositories/index.ts
================================================
export { WeaponRepository } from '@Repositories/Weapon';
export { PlanetRepository } from '@Repositories/Planet';


================================================
FILE: src/ServiceHelpers/AttackHelper.ts
================================================
//#region Global Imports
import { Context } from 'moleculer';
//#endregion Global Imports

//#region Interface Imports
import { IAttack } from '@Interfaces';
//#endregion Interface Imports

export namespace AttackHelper {
	const prefix: string = 'attack';

	export const Fire = async (
		ctx: Context,
		params: IAttack.FireInDto,
	): Promise<IAttack.FireOutDto> => await ctx.call(`${prefix}.Fire`, params);
}


================================================
FILE: src/ServiceHelpers/PlanetHelper.ts
================================================
//#region Global Imports
import { Context } from 'moleculer';
//#endregion Global Imports

//#region Interface Imports
import { IPlanet } from '@Interfaces';
//#endregion Interface Imports

export namespace PlanetHelper {
	const prefix: string = 'planet';

	export const Defend = async (
		ctx: Context,
		params: IPlanet.DefendInDto,
	): Promise<IPlanet.DefendOutDto> => await ctx.call(`${prefix}.Defend`, params);
}


================================================
FILE: src/ServiceHelpers/index.ts
================================================
export { AttackHelper } from '@ServiceHelpers/AttackHelper';
export { PlanetHelper } from '@ServiceHelpers/PlanetHelper';


================================================
FILE: swagger/config.js
================================================
const swaggerJSDoc = require('swagger-jsdoc');

const swaggerDefinition = {
	info: {
		title: 'Pankod MoleculerJS Boilerplate', // Title of the documentation
		version: '1.0.0', // Version of the app
		description:
			'Moleculer JS Microservice Boilerplate with Typescript, TypeORM, CLI, Service Clients, Swagger, Jest, Docker, Eslint support and everything you will ever need to deploy rock solid projects..', // short description of the app
	},
	host: 'localhost:3000', // the host or url of the app
	basePath: '/api', // the basepath of your endpoint
};

// options for the swagger docs
const options = {
	// import swaggerDefinitions
	definition: swaggerDefinition,
	explorer: true,

	// path to the API docs
	apis: ['./*.service.ts'],
};
// initialize swagger-jsdoc
const swaggerSpec = swaggerJSDoc(options);

module.exports = swaggerSpec;


================================================
FILE: swagger/index.js
================================================
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const cors = require('cors');
const bodyParser = require('body-parser');

const swaggerFile = require('./swagger.json');
const app = express();

app.use(function (req, res, next) {
	res.header("Access-Control-Allow-Origin", "*");
	res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
	res.header('Access-Control-Allow-Credentials', 'true');
	next();
});

app.use(cors());
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies

const PORT = 3001;

const options = {
	explorer: true,
	enableCORS: false
};

app.use('/', swaggerUi.serve, swaggerUi.setup(swaggerFile, options));

app.listen(PORT, () =>
	console.log(`swagger ui listening on port ${PORT}!`),
);

================================================
FILE: swagger/package.json
================================================
{
	"main": "index.js"
}

================================================
FILE: swagger/swagger.json
================================================
{
  "info": {
    "title": "Pankod MoleculerJS Boilerplate",
    "version": "1.0.0",
    "description": "Moleculer JS Microservice Boilerplate with Typescript, TypeORM, CLI, Service Clients, Swagger, Jest, Docker, Eslint support and everything you will ever need to deploy rock solid projects.."
  },
  "host": "localhost:3000",
  "basePath": "/api",
  "swagger": "2.0",
  "paths": {
    "/attack/Fire": {
      "post": {
        "description": "Attacks to the planet with given weapon.",
        "produces": [
          "application/json"
        ],
        "consumes": [
          "application/json"
        ],
        "parameters": [
          {
            "in": "body",
            "name": "params",
            "schema": {
              "type": "object",
              "required": [
                "weaponName",
                "planetName"
              ],
              "properties": {
                "weaponName": {
                  "type": "string",
                  "example": "Death Star"
                },
                "planetName": {
                  "type": "string",
                  "example": "Alderaan"
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Example attack result"
          },
          "422": {
            "description": "Missing parameters"
          }
        }
      }
    },
    "/planet/Defend": {
      "post": {
        "description": "Attacks to the planet with given weapon.",
        "produces": [
          "application/json"
        ],
        "consumes": [
          "application/json"
        ],
        "parameters": [
          {
            "in": "body",
            "name": "params",
            "schema": {
              "type": "object",
              "required": [
                "weaponName",
                "planetName"
              ],
              "properties": {
                "weaponName": {
                  "type": "string",
                  "example": "Death Star"
                },
                "planetName": {
                  "type": "string",
                  "example": "Alderaan"
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Example attack result"
          },
          "422": {
            "description": "Missing parameters"
          }
        }
      }
    }
  },
  "definitions": {},
  "responses": {},
  "parameters": {},
  "securityDefinitions": {},
  "tags": []
}

================================================
FILE: swaggerConfig.json
================================================
{
	"swagger": {
		"baseUrl": "./",
		"outputDirectory": "./swagger",
		"entryFile": "./services/index.ts",
		"host": "localhost:3000",
		"basePath": "/api",
		"securityDefinitions": {
			"api_key": {
				"type": "apiKey",
				"name": "access_token",
				"in": "query"
			},
			"tsoa_auth": {
				"type": "oauth2",
				"authorizationUrl": "http://swagger.io/api/oauth/dialog",
				"flow": "implicit",
				"scopes": {
					"write:pets": "modify things",
					"read:pets": "read things"
				}
			}
		},
		"yaml": true
	}
}

================================================
FILE: test/Config/Connection.ts
================================================
//#region Global Imports
import { createConnection, Connection } from 'typeorm';
//#region Global Imports

export default async (): Promise<Connection | undefined> => {
	try {
		return await createConnection({
			type: 'sqlite',
			name: 'default',
			database: ':memory:',
			entities: ['./src/Entities/*.ts'],
			synchronize: true,
			dropSchema: true,
		});
	} catch (error) {
		return undefined;
	}
};


================================================
FILE: test/Config/SetupDatabase.ts
================================================
//#region Local Imports
import Seeder from '../Seeder';
import CreateConnection from './Connection';
//#region Local Imports

const setupDatabase = async (): Promise<void> => {
	await CreateConnection();

	await Seeder.seed();
};

export default setupDatabase;


================================================
FILE: test/Config/mock.setup.ts
================================================


================================================
FILE: test/Integration/attack.spec.ts
================================================
//#region Global Imports
import ApiGateway = require('moleculer-web');
import { getConnection } from 'typeorm';
import request from 'supertest';
//#endregion Global Imports

//#region Local Imports
import setupDatabase from '@Test/Config/SetupDatabase';
import { BrokerHelper } from '@Test/Utils';
import * as supertest from 'supertest';
//#endregion Local Imports

const broker = BrokerHelper.setupBroker();
let server: {};

beforeEach(async () => {
	await setupDatabase();
});

afterEach(async () => {
	await getConnection().close();
});

beforeAll(async () => {
	const service = broker.createService(ApiGateway);
	server = service.server;
	return broker.start();
});

afterAll(async () => broker.stop());

describe('Test Attack service requests', () => {
	it('Test POST request on attack service Fire method', async () => {
		const params = {
			planetName: 'Alderaan',
			weaponName: 'Death Star',
		};

		return request(server)
			.post('/attack/Fire')
			.query({ ...params })
			.then((res: supertest.Response) => {
				expect(res.status).toBe(200);
				expect(res.header['content-type']).toBe('application/json; charset=utf-8');
				expect(res.body.planetMessage).toContain('Planet took');
				expect(res.body.weaponMessage).toContain('Death Star did');
			});
	});
});


================================================
FILE: test/Integration/planet.spec.ts
================================================
//#region Global Imports
import ApiGateway = require('moleculer-web');
import { getConnection } from 'typeorm';
import request from 'supertest';
//#endregion Global Imports

//#region Local Imports
import setupDatabase from '@Test/Config/SetupDatabase';
import { BrokerHelper } from '@Test/Utils';
import * as supertest from 'supertest';
//#endregion Local Imports

const broker = BrokerHelper.setupBroker();
let server: {};

beforeEach(async () => {
	await setupDatabase();
});

afterEach(async () => {
	await getConnection().close();
});

beforeAll(async () => {
	const service = broker.createService(ApiGateway);
	server = service.server;
	return broker.start();
});

afterAll(async () => broker.stop());

describe('Test Planet service requests', () => {
	it('Test POST request on planet service Defend method', async () => {
		const params = {
			planetName: 'Alderaan',
			weaponName: 'Death Star',
		};

		return request(server)
			.post('/planet/Defend')
			.query({ ...params })
			.then((res: supertest.Response) => {
				expect(res.status).toBe(200);
				expect(res.header['content-type']).toBe('application/json; charset=utf-8');
				expect(res.body.planetMessage).toContain('Planet took');
			});
	});
});


================================================
FILE: test/Seeder/AttackSeeder.ts
================================================
//#region Global Imports
import { getManager } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import { Weapon } from '@Entities/Weapon';
//#region Local Imports

const seed = async (): Promise<void> => {
	const entityManager = getManager();
	await entityManager.insert(Weapon, { name: 'Death Star', ammo: 1000, damage: 1000 });
};

export default {
	seed,
};


================================================
FILE: test/Seeder/PlanetSeeder.ts
================================================
//#region Global Imports
import { getManager } from 'typeorm';
//#region Global Imports

//#region Local Imports
import { Planet } from '@Entities/Planet';
//#region Local Imports

const seed = async (): Promise<void> => {
	const entityManager = getManager();
	await entityManager.insert(Planet, { name: 'Alderaan', shield: 100000 });
};

export default {
	seed,
};


================================================
FILE: test/Seeder/index.ts
================================================
//#region Local Imports
import PlanetSeeder from './PlanetSeeder';
import AttackSeeder from './AttackSeeder';
//#region Local Imports

const seed = async (): Promise<void> => {
	await PlanetSeeder.seed();
	await AttackSeeder.seed();
};

export default {
	seed,
};


================================================
FILE: test/Unit/Entities/Connection.spec.ts
================================================
import CreateConnection from '../../../src/Entities/Connection';
import { Connection, getConnection } from 'typeorm';

describe('Connection', async () => {
	it('should return connection and connect', async () => {
		const connection = await CreateConnection();

		expect(connection).toBeInstanceOf(Connection);
		expect(getConnection().isConnected).toBe(true);
	});

	it('should not fail for 2nd connection', async () => {
		await CreateConnection();

		expect(async () => await CreateConnection()).not.toThrow();
	});
});


================================================
FILE: test/Unit/Meta/CalculateMeta.spec.ts
================================================
//#region Global Imports
import { getManager, getConnection } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import setupDatabase from '@Test/Config/SetupDatabase';
import { CalculateMeta } from '@Meta';
import { Planet, Weapon } from '@Entities';
//#endregion Local Imports

describe('CalculateMeta constructor', () => {
	it('should be defined', () => {
		expect(CalculateMeta).toBeDefined();
	});
});

describe('CalculateMeta functions', () => {
	beforeEach(async () => {
		await setupDatabase();
	});

	afterEach(async () => {
		await getConnection().close();
	});

	it('should calculate remaining shield', async () => {
		const entityManager = getManager();

		const weapon = await entityManager.findOne(Weapon, { where: { name: 'Death Star' } });
		const planet = await entityManager.findOne(Planet, { where: { name: 'Alderaan' } });

		const { damage, remainingShield } = await CalculateMeta.Damage(weapon!, planet!);

		expect(remainingShield).toEqual(planet!.shield - damage);
	});
});


================================================
FILE: test/Unit/MicroServices/attack.spec.ts
================================================
//#region Global Imports
import { getManager } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import setupDatabase from '@Test/Config/SetupDatabase';
import { AttackHelper } from '@ServiceHelpers';
import { Weapon } from '@Entities';
import { BrokerHelper } from '@Test/Utils';
import { IAttack } from '@Interfaces';
//#endregion Local Imports

const broker = BrokerHelper.setupBroker();

beforeEach(async () => {
	await broker.start();
	await setupDatabase();
});

afterEach(async () => {
	await broker.stop();
});

describe('Test attack service', () => {
	const params: IAttack.FireInDto = {
		planetName: 'Alderaan',
		weaponName: 'Death Star',
	};

	describe('Fire method', async () => {
		it('when ammo is up', async () => {
			// eslint-disable-next-line
			const { planetMessage, weaponMessage } = await AttackHelper.Fire(broker as any, params);

			expect(planetMessage).toContain('Planet took');
			expect(weaponMessage).toContain('Death Star did');
		});

		it('when ammo is empty', async () => {
			getManager().update(Weapon, { name: 'Death Star' }, { ammo: 0 });

			// eslint-disable-next-line
			const { planetMessage, weaponMessage } = await AttackHelper.Fire(broker as any, params);

			expect(planetMessage).toEqual('Planet took no damage');
			expect(weaponMessage).toEqual('This weapon has no ammo');
		});
	});
});


================================================
FILE: test/Unit/MicroServices/planet.spec.ts
================================================
//#region Global Imports
import { getManager } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import setupDatabase from '@Test/Config/SetupDatabase';
import { PlanetHelper } from '@ServiceHelpers';
import { Planet } from '@Entities/Planet';
import { BrokerHelper } from '@Test/Utils';
import { IPlanet } from '@Interfaces';
//#endregion Local Imports

const broker = BrokerHelper.setupBroker();

beforeEach(async () => {
	await broker.start();
	await setupDatabase();
});

afterEach(async () => {
	await broker.stop();
});

describe('Test Defend service', () => {
	describe('Defend method', async () => {
		const params: IPlanet.DefendInDto = {
			planetName: 'Alderaan',
			weaponName: 'Death Star',
		};

		it('when shield is up', async () => {
			// eslint-disable-next-line
			const { planetMessage } = await PlanetHelper.Defend(broker as any, params);

			expect(planetMessage).toContain('Planet took');
		});

		it('when shield is down', async () => {
			getManager().update(Planet, { name: 'Alderaan' }, { shield: 1 });

			/* eslint-disable */
			// First fire to break shield entirely
			await PlanetHelper.Defend(broker as any, params);
			const { planetMessage } = await PlanetHelper.Defend(broker as any, params);
			/* eslint-enable */

			expect(planetMessage).toEqual('Planet shield ruined! war is lost!');
		});
	});
});


================================================
FILE: test/Unit/Repositories/ErrorHelpers.spec.ts
================================================
//#region Global Imports
import { Errors } from 'moleculer';
//#endregion Global Imports

//#region Local Imports
import { Throw404 } from '@Repositories/ErrorHelpers';
//#endregion Local Imports

describe('Throw 404', () => {
	it('should be defined', () => {
		expect(Throw404).toBeDefined();
	});

	it('shouldnt throw error if resource is present', () => {
		expect(() => Throw404({ resource: 'test' }, 'Test Error')).not.toThrow();
	});

	it('should throw error when resource not present', () => {
		expect(() => Throw404(undefined, 'Test Error')).toThrowError(Errors.MoleculerError);
	});
});


================================================
FILE: test/Unit/Repositories/Planet.spec.ts
================================================
//#region Global Imports
import { getConnection } from 'typeorm';
//#endregion Global Imports

//#region Local Imports
import setupDatabase from '@Test/Config/SetupDatabase';
import { PlanetRepository } from '@Repositories';
//#endregion Local Imports

describe('Planet Repository Constructor', () => {
	it('should be defined', () => {
		expect(PlanetRepository).toBeDefined();
	});
});

describe('Planet Repository Methods', () => {
	beforeEach(async () => {
		await setupDatabase();
	});

	afterEach(async () => {
		await getConnection().close();
	});

	describe('Get', () => {
		it('should get planet if there is any', async () => {
			const planetName = 'Alderaan';

			const planet = await PlanetRepository.Get(planetName);

			expect(planet.name).toEqual(planetName);
		});

		it('should raise error', async () => {
			const planetName = 'I dont exist';

			expect(async () => PlanetRepository.Get(planetName)).toThrowError;
		});
	});

	it('should update shield', async () => {
		const planetName = 'Alderaan';

		const expectedShield = 1000;

		const { remainingShield } = await PlanetRepository.DecreaseShield(
			planetName,
			expectedShield,
		);

		expect(remainingShield).toEqual(expectedShield);
	});
});


================================================
FILE: test/Unit/Repositories/Weapon.spec.ts
================================================
//#region Global Imports
import { getManager, getConnection } from 'typeorm';
//#region Global Imports

//#region Local Imports
import setupDatabase from '@Test/Config/SetupDatabase';
import { WeaponRepository } from '@Repositories';
import { Weapon } from '@Entities';
//#endregion Local Imports

describe('Test WeaponRepository constructor', () => {
	it('should be defined', () => {
		expect(WeaponRepository).toBeDefined();
	});
});

describe('Weapon Repository Methods', () => {
	beforeEach(async () => {
		await setupDatabase();
	});

	afterEach(async () => {
		await getConnection().close();
	});

	describe('GetWeapon', async () => {
		it('should get weapon', async () => {
			const weaponName = 'Death Star';

			const weapon = await WeaponRepository.Get(weaponName);

			expect(weapon.name).toEqual(weaponName);
		});

		it('should throw an error if weapon not found', async () => {
			const weaponName = `I don't exist`;

			await expect(WeaponRepository.Get(weaponName)).rejects.toThrow(
				'{"name":"I don\'t exist"}',
			);
		});
	});

	it('Decrease Ammo', async () => {
		const entityManager = getManager();

		const weaponName = 'Death Star';
		const weapon = await entityManager.findOne(Weapon, { where: { name: weaponName } });

		const expectedAmmo = weapon!.ammo - 1;

		const { remainingAmmo } = await WeaponRepository.DecreaseAmmo(weaponName);

		expect(remainingAmmo).toEqual(expectedAmmo);
	});
});


================================================
FILE: test/Unit/ServiceHelpers/AttackHelper.spec.ts
================================================
//#region Local Imports
import { AttackHelper } from '@ServiceHelpers';
import { DummyContext } from '@Test/Utils';
//#endregion Local Imports

//#region Interface Imports
import { IAttack } from '@Interfaces';
//#region Interface Imports

describe('Weapon helper service helper constructor', () => {
	it('should be defined', async () => {
		expect(AttackHelper).toBeDefined();
	});
});

describe('Weapon service helpers', () => {
	it('should trigger Fire method', async () => {
		const params: IAttack.FireInDto = {
			weaponName: 'Death Star',
			planetName: 'Alderaan',
		};

		const result = await AttackHelper.Fire(DummyContext.getCall(params), params);

		expect(result).toBeDefined();
	});
});


================================================
FILE: test/Unit/ServiceHelpers/PlanetHelper.spec.ts
================================================
//#region Local Imports
import { PlanetHelper } from '@ServiceHelpers';
import { DummyContext } from '@Test/Utils';
//#region Local Imports

//#region Interface Imports
import { IPlanet } from '@Interfaces';
//#region Interface Imports

describe('Planet service helper constructor', () => {
	it('should be defined', async () => {
		expect(PlanetHelper).toBeDefined();
	});
});

describe('Planet service helpers', () => {
	it('should trigger Defend method', async () => {
		const params: IPlanet.DefendInDto = {
			weaponName: 'Death Star',
			planetName: 'Alderaan',
		};

		const result = await PlanetHelper.Defend(DummyContext.getCall(params), params);

		expect(result).toBeDefined();
	});
});


================================================
FILE: test/Utils/BrokerHelper.ts
================================================
//#region Global Imports
import { ServiceBroker } from 'moleculer';
//#endregion Global Imports

/* eslint-disable */
//#region Local Imports
const AttackService = require('../../services/attack.service');
const PlanetService = require('../../services/planet.service');
//#endregion Local Imports
/* eslint-enable */

export namespace BrokerHelper {
	export const setupBroker = () => {
		const broker = new ServiceBroker({ logger: false });

		broker.createService(AttackService);
		broker.createService(PlanetService);

		return broker;
	};
}


================================================
FILE: test/Utils/DummyContext.spec.ts
================================================
import { DummyContext } from './DummyContext';
import { Context } from 'moleculer';

describe('Dummy Context', async () => {
	it('should define getCall', async () => {
		const ctx = DummyContext.getCall({});

		expect(ctx).toBeInstanceOf(Context);
		expect(ctx.call).toBeDefined();
		expect(await ctx.call('test', {})).toEqual({});
	});
});


================================================
FILE: test/Utils/DummyContext.ts
================================================
//#region Global Imports
import { Context, Endpoint, ServiceBroker } from 'moleculer';
//#endregion Global Imports

export namespace DummyContext {
	const broker = new ServiceBroker({ logger: false, maxCallLevel: 5 });

	const endpoint: Endpoint = {
		broker,
		id: 'server-123',
		node: {},
		local: true,
		state: false,
	};

	export const getCall = (data: object) => {
		const ctx = Context.create(broker, endpoint, data);
		// eslint-disable-next-line
		ctx.call = jest.fn(async () => (broker.Promise as any).resolve({}));

		return ctx;
	};
}


================================================
FILE: test/Utils/index.ts
================================================
export { DummyContext } from './DummyContext';
export { BrokerHelper } from './BrokerHelper';


================================================
FILE: tsconfig.json
================================================
{
	"compilerOptions": {
		"experimentalDecorators": true,
		"emitDecoratorMetadata": true,
		"esModuleInterop": true,
		"noImplicitAny": true,
		"noImplicitReturns": true,
		"noImplicitThis": true,
		"strict": true,
		"module": "commonjs",
		"pretty": true,
		"types": [
			"jest",
			"node"
		],
		"outDir": "dist",
		"sourceMap": true,
		"target": "es6",
		"allowJs": true,
		"baseUrl": ".",
		"paths": {
			"@MicroServices/*": [
				"services/*"
			],
			"@MicroServices": [
				"services"
			],
			"@Interfaces/*": [
				"src/Interfaces/*"
			],
			"@Interfaces": [
				"src/Interfaces"
			],
			"@Repositories/*": [
				"src/Repositories/*"
			],
			"@Repositories": [
				"src/Repositories"
			],
			"@ServiceHelpers/*": [
				"src/ServiceHelpers/*"
			],
			"@ServiceHelpers": [
				"src/ServiceHelpers"
			],
			"@Meta/*": [
				"src/Meta/*"
			],
			"@Meta": [
				"src/Meta"
			],
			"@Entities/*": [
				"src/Entities/*"
			],
			"@Entities": [
				"src/Entities"
			],
			"@Test/*": [
				"test/*"
			],
			"@Test": [
				"test"
			]
		}
	},
	"exclude": [
		"node_modules"
	],
	"include": [
		"./src/**/*.ts",
		"./services/**/*.ts",
		"./test/**/*.ts"
	]
}


================================================
FILE: tsconfig.production.json
================================================
{
	"extends": "./tsconfig",
	"compilerOptions": {
		"baseUrl": "./dist",
	},
}
Download .txt
gitextract_izw2cz6n/

├── .dockerignore
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── .travis.yml
├── Dockerfile
├── LICENSE
├── README.md
├── db.sqlite.example
├── docker-compose.env
├── docker-compose.yml
├── documentation/
│   ├── Dockerfile
│   ├── README.md
│   ├── docker-compose.yml
│   ├── docs/
│   │   ├── cli-migration-guide.md
│   │   ├── cli-overview.md
│   │   ├── cli-usage.md
│   │   ├── deployment.md
│   │   ├── eslint.md
│   │   ├── example.md
│   │   ├── features.md
│   │   ├── getting-started.md
│   │   ├── setup.md
│   │   ├── structure.md
│   │   ├── swagger.md
│   │   ├── testing.md
│   │   └── typeorm.md
│   └── website/
│       ├── config.yml
│       ├── core/
│       │   └── Footer.js
│       ├── docs.json
│       ├── i18n/
│       │   └── en.json
│       ├── package.json
│       ├── pages/
│       │   └── en/
│       │       ├── help.js
│       │       ├── index.js
│       │       └── users.js
│       ├── sidebars.json
│       ├── siteConfig.js
│       └── static/
│           └── css/
│               └── custom.css
├── moleculer.config.ts
├── package.json
├── public/
│   └── index.html
├── services/
│   ├── api.service.ts
│   ├── attack.service.ts
│   ├── index.ts
│   └── planet.service.ts
├── src/
│   ├── Entities/
│   │   ├── Connection.ts
│   │   ├── Planet.ts
│   │   ├── Weapon.ts
│   │   └── index.ts
│   ├── Interfaces/
│   │   ├── Meta/
│   │   │   ├── DamageMetaOutDto.d.ts
│   │   │   └── index.ts
│   │   ├── Repositories/
│   │   │   ├── Planet/
│   │   │   │   ├── DecreaseShieldOutDto.d.ts
│   │   │   │   └── index.ts
│   │   │   └── Weapon/
│   │   │       ├── DecreaseAmmoOutDto.d.ts
│   │   │       └── index.ts
│   │   ├── Services/
│   │   │   ├── Attack/
│   │   │   │   ├── IAttack.d.ts
│   │   │   │   └── index.ts
│   │   │   └── Planet/
│   │   │       ├── IPlanet.d.ts
│   │   │       └── index.ts
│   │   └── index.ts
│   ├── Meta/
│   │   ├── CalculateMeta.ts
│   │   └── index.ts
│   ├── Repositories/
│   │   ├── ErrorHelpers.ts
│   │   ├── Planet.ts
│   │   ├── Shared.ts
│   │   ├── Weapon.ts
│   │   └── index.ts
│   └── ServiceHelpers/
│       ├── AttackHelper.ts
│       ├── PlanetHelper.ts
│       └── index.ts
├── swagger/
│   ├── config.js
│   ├── index.js
│   ├── package.json
│   └── swagger.json
├── swaggerConfig.json
├── test/
│   ├── Config/
│   │   ├── Connection.ts
│   │   ├── SetupDatabase.ts
│   │   └── mock.setup.ts
│   ├── Integration/
│   │   ├── attack.spec.ts
│   │   └── planet.spec.ts
│   ├── Seeder/
│   │   ├── AttackSeeder.ts
│   │   ├── PlanetSeeder.ts
│   │   └── index.ts
│   ├── Unit/
│   │   ├── Entities/
│   │   │   └── Connection.spec.ts
│   │   ├── Meta/
│   │   │   └── CalculateMeta.spec.ts
│   │   ├── MicroServices/
│   │   │   ├── attack.spec.ts
│   │   │   └── planet.spec.ts
│   │   ├── Repositories/
│   │   │   ├── ErrorHelpers.spec.ts
│   │   │   ├── Planet.spec.ts
│   │   │   └── Weapon.spec.ts
│   │   └── ServiceHelpers/
│   │       ├── AttackHelper.spec.ts
│   │       └── PlanetHelper.spec.ts
│   └── Utils/
│       ├── BrokerHelper.ts
│       ├── DummyContext.spec.ts
│       ├── DummyContext.ts
│       └── index.ts
├── tsconfig.json
└── tsconfig.production.json
Download .txt
SYMBOL INDEX (37 symbols across 15 files)

FILE: documentation/website/core/Footer.js
  class Footer (line 12) | class Footer extends React.Component {
    method constructor (line 14) | constructor() {
    method docUrl (line 21) | docUrl(doc, language) {
    method pageUrl (line 29) | pageUrl(doc, language) {
    method render (line 34) | render() {

FILE: documentation/website/pages/en/help.js
  function Help (line 15) | function Help(props) {

FILE: documentation/website/pages/en/index.js
  class HomeSplash (line 16) | class HomeSplash extends React.Component {
    method render (line 17) | render() {
  class Index (line 84) | class Index extends React.Component {
    method render (line 85) | render() {

FILE: documentation/website/pages/en/users.js
  class Users (line 14) | class Users extends React.Component {
    method render (line 15) | render() {

FILE: moleculer.config.ts
  method created (line 145) | created(broker) {}
  method started (line 149) | started(broker) {}
  method stopped (line 153) | stopped(broker) {}

FILE: services/attack.service.ts
  class AttackService (line 18) | @Service({
    method started (line 22) | public async started() {
    method Fire (line 32) | public async Fire(ctx: Context<IAttack.FireInDto>): Promise<IAttack.Fi...
    method FireMethod (line 70) | public async FireMethod(ctx: Context<IAttack.FireInDto>): Promise<IAtt...
    method stopped (line 96) | public async stopped() {

FILE: services/planet.service.ts
  class PlanetService (line 18) | @Service({
    method started (line 22) | public async started() {
    method Defend (line 32) | public async Defend(ctx: Context<IPlanet.DefendInDto>): Promise<IPlane...
    method DefendMethod (line 70) | public async DefendMethod(ctx: Context<IPlanet.DefendInDto>): Promise<...
    method stopped (line 91) | public async stopped() {

FILE: src/Entities/Planet.ts
  class Planet (line 6) | class Planet {
    method constructor (line 16) | constructor(name: string, shield: number) {

FILE: src/Entities/Weapon.ts
  class Weapon (line 6) | class Weapon {
    method constructor (line 19) | constructor(name: string, damage: number, ammo: number) {

FILE: src/Interfaces/Meta/DamageMetaOutDto.d.ts
  type DamageMetaOutDto (line 1) | interface DamageMetaOutDto {

FILE: src/Interfaces/Repositories/Planet/DecreaseShieldOutDto.d.ts
  type DecreaseShieldOutDto (line 1) | interface DecreaseShieldOutDto {

FILE: src/Interfaces/Repositories/Weapon/DecreaseAmmoOutDto.d.ts
  type DecreaseAmmoOutDto (line 1) | interface DecreaseAmmoOutDto {

FILE: src/Interfaces/Services/Attack/IAttack.d.ts
  type FireInDto (line 2) | interface FireInDto {
  type FireOutDto (line 7) | interface FireOutDto {

FILE: src/Interfaces/Services/Planet/IPlanet.d.ts
  type DefendInDto (line 2) | interface DefendInDto {
  type DefendOutDto (line 7) | interface DefendOutDto {

FILE: swagger/index.js
  constant PORT (line 20) | const PORT = 3001;
Condensed preview — 99 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (113K chars).
[
  {
    "path": ".dockerignore",
    "chars": 44,
    "preview": "node_modules\ndist\nproject-cli\ndocumentation\n"
  },
  {
    "path": ".editorconfig",
    "chars": 166,
    "preview": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ncharset = utf-8\nindent_style = tab\nindent_size = 4\n\n[packa"
  },
  {
    "path": ".eslintrc.js",
    "chars": 2439,
    "preview": "module.exports = {\n\tparser: '@typescript-eslint/parser',\n\textends: [\n\t\t'plugin:@typescript-eslint/recommended',\n\t\t'prett"
  },
  {
    "path": ".gitignore",
    "chars": 1031,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directo"
  },
  {
    "path": ".prettierrc",
    "chars": 119,
    "preview": "{\n\t\"semi\": true,\n\t\"trailingComma\": \"all\",\n\t\"singleQuote\": true,\n\t\"printWidth\": 100,\n\t\"tabWidth\": 4,\n\t\"useTabs\": true\n}\n"
  },
  {
    "path": ".travis.yml",
    "chars": 377,
    "preview": "language: node_js\nnode_js:\n  - \"10\"\ninstall:\n  - npm ci\nscript:\n  - npm run lint\n  - npm run test\nbefore_script:\n  - cur"
  },
  {
    "path": "Dockerfile",
    "chars": 186,
    "preview": "FROM node:10-alpine\n\nRUN mkdir /app\nWORKDIR /app\n\nCOPY package*.json ./\n\nRUN npm ci \n\nCOPY . .\n\nRUN npm run build && npm"
  },
  {
    "path": "LICENSE",
    "chars": 1063,
    "preview": "MIT License\n\nCopyright (c) 2019 Pankod\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
  },
  {
    "path": "README.md",
    "chars": 4093,
    "preview": "<img src=\"moleculerjs-cover.png\" alt=\"Moleculer JS Microservice Boilerplate with Typescript, TypeORM, CLI, Service Clien"
  },
  {
    "path": "docker-compose.env",
    "chars": 100,
    "preview": "NAMESPACE=\nLOGGER=true\nLOGLEVEL=info\nSERVICEDIR=dist/services\n\nTRANSPORTER=nats://nats-server:4222\n\n"
  },
  {
    "path": "docker-compose.yml",
    "chars": 480,
    "preview": "version: \"3.0\"\n\nservices:\n\n  api:\n    build: .\n    image: api\n    env_file: docker-compose.env\n    environment:\n      SE"
  },
  {
    "path": "documentation/Dockerfile",
    "chars": 148,
    "preview": "FROM node:8.11.4\n\nWORKDIR /app/website\n\nEXPOSE 3000 35729\nCOPY ./docs /app/docs\nCOPY ./website /app/website\nRUN yarn ins"
  },
  {
    "path": "documentation/README.md",
    "chars": 564,
    "preview": "<img src=\"https://github.com/pankod/docusaurus-boilerplate/blob/master/demo.png\" alt=\"Pankod - docusaurus-boilerplate\" a"
  },
  {
    "path": "documentation/docker-compose.yml",
    "chars": 497,
    "preview": "version: \"3\"\n\nservices:\n  docusaurus:\n    build: .\n    ports:\n      - 3000:3000\n      - 35729:35729\n    volumes:\n      -"
  },
  {
    "path": "documentation/docs/cli-migration-guide.md",
    "chars": 754,
    "preview": "---\nid: cli-migration-guide\ntitle: CLI Migrate Guide\nsidebar_label: Migration Guide\n---\n\nInitially, moleculer's `project"
  },
  {
    "path": "documentation/docs/cli-overview.md",
    "chars": 562,
    "preview": "---\nid: cli-overview\ntitle: Overview\nsidebar_label: Overview\n---\n\n\n<div>\n <img width=\"600\" src=\"assets/cli.gif\" >\n</div>"
  },
  {
    "path": "documentation/docs/cli-usage.md",
    "chars": 1607,
    "preview": "---\nid: cli-usage\ntitle: Usage\nsidebar_label: Usage\n---\n\n\nAfter starting, an interactive menu will let you file to be cr"
  },
  {
    "path": "documentation/docs/deployment.md",
    "chars": 1184,
    "preview": "---\nid: deployment\ntitle: Deployment\nsidebar_label: Deployment\n---\n\n## Build\n\nBuilds the app for production into the dis"
  },
  {
    "path": "documentation/docs/eslint.md",
    "chars": 299,
    "preview": "---\nid: eslint\ntitle: Usage\nsidebar_label: ESLint\n---\n\nESLint integrated to boilerplate for linting.\n\nLints with Eslint."
  },
  {
    "path": "documentation/docs/example.md",
    "chars": 5149,
    "preview": "---\nid: example-app\ntitle: Example App\nsidebar_label: Example App\n---\n<br>\n<img src=\"assets/alderaan.png\" align=\"center\""
  },
  {
    "path": "documentation/docs/features.md",
    "chars": 1157,
    "preview": "---\nid: features\ntitle: What's included?\n---\n\n\nmoleculerjs-boilerplate project provides a lot of features out of the box"
  },
  {
    "path": "documentation/docs/getting-started.md",
    "chars": 1386,
    "preview": "---\nid: getting-started\ntitle: Getting Started\nsidebar_label: Getting Started\n---\n\n## About Moleculer\n\nMoleculer is a fa"
  },
  {
    "path": "documentation/docs/setup.md",
    "chars": 771,
    "preview": "---\nid: setup\ntitle: Setup\n---\nTo create a new app, you may choose one of the following methods:\n#### Clone the reposito"
  },
  {
    "path": "documentation/docs/structure.md",
    "chars": 2415,
    "preview": "---\nid: structure\ntitle: Structure\nsidebar_label: Structure\n---\n\nAfter the setup is complete, your app should have the f"
  },
  {
    "path": "documentation/docs/swagger.md",
    "chars": 1354,
    "preview": "---\nid: swagger\ntitle: Usage\nsidebar_label: Swagger\n---\n\n`swagger-jsdoc` is a library which returns the validated OpenAP"
  },
  {
    "path": "documentation/docs/testing.md",
    "chars": 4436,
    "preview": "---\nid: testing\ntitle: Testing\nsidebar_label: Testing\n---\n\nThis boilerplate uses [Jest](https://jestjs.io/docs/en/gettin"
  },
  {
    "path": "documentation/docs/typeorm.md",
    "chars": 1536,
    "preview": "---\nid: typeorm\ntitle: TypeORM & Repository\nsidebar_label: TypeORM\n---\n\n`createConnection` method in  `src/Entities/Conn"
  },
  {
    "path": "documentation/website/config.yml",
    "chars": 37,
    "preview": "GIT_USER=docusaurus-bot\nUSE_SSH=true\n"
  },
  {
    "path": "documentation/website/core/Footer.js",
    "chars": 2954,
    "preview": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n"
  },
  {
    "path": "documentation/website/docs.json",
    "chars": 284,
    "preview": "[\n\t{\n\t\t\"id\": \"getting-started\",\n\t\t\"title\": \"Getting Started\"\n\t},\n\t{\n\t\t\"id\": \"example-app\",\n\t\t\"title\": \"Example App\",\n\t\t\""
  },
  {
    "path": "documentation/website/i18n/en.json",
    "chars": 2095,
    "preview": "{\n  \"_comment\": \"This file is auto-generated by write-translations.js\",\n  \"localized-strings\": {\n    \"next\": \"Next\",\n   "
  },
  {
    "path": "documentation/website/package.json",
    "chars": 355,
    "preview": "{\n\t\"scripts\": {\n\t\t\"examples\": \"docusaurus-examples\",\n\t\t\"start\": \"docusaurus-start\",\n\t\t\"build\": \"docusaurus-build\",\n\t\t\"pu"
  },
  {
    "path": "documentation/website/pages/en/help.js",
    "chars": 1444,
    "preview": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n"
  },
  {
    "path": "documentation/website/pages/en/index.js",
    "chars": 6460,
    "preview": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n"
  },
  {
    "path": "documentation/website/pages/en/users.js",
    "chars": 1242,
    "preview": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n"
  },
  {
    "path": "documentation/website/sidebars.json",
    "chars": 320,
    "preview": "{\n\t\"docs\": {\n\t\t\"Introduction\": [\n\t\t\t\"getting-started\",\n\t\t\t\"features\"\n\t\t],\n\t\t\"Overview\": [\n\t\t\t\"setup\",\n\t\t\t\"example-app\",\n"
  },
  {
    "path": "documentation/website/siteConfig.js",
    "chars": 3713,
    "preview": "/**\n * Copyright (c) 2017-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n"
  },
  {
    "path": "documentation/website/static/css/custom.css",
    "chars": 727,
    "preview": "/* your custom css */\n.nav-footer {\n\tbackground-color: #2c3e50;\n}\n\n.gridBlock {\n\talign-items: baseline;\n}\n.top-badges {\n"
  },
  {
    "path": "moleculer.config.ts",
    "chars": 5816,
    "preview": "'use strict';\nimport { BrokerOptions } from 'moleculer';\nimport 'reflect-metadata';\nimport * as Moleculer from 'molecule"
  },
  {
    "path": "package.json",
    "chars": 2818,
    "preview": "{\n  \"name\": \"moleculerjs-boilerplate\",\n  \"version\": \"1.0.0\",\n  \"description\": \"My Moleculer microservices project\",\n  \"s"
  },
  {
    "path": "public/index.html",
    "chars": 2627,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\" />\n\t\t<title>MoleculerJS Boilerplate | Pankod</title>\n\t\t"
  },
  {
    "path": "services/api.service.ts",
    "chars": 627,
    "preview": "//#region Global Imports\nimport { ServiceSchema } from 'moleculer';\nimport ApiGateway = require('moleculer-web');\n//#end"
  },
  {
    "path": "services/attack.service.ts",
    "chars": 2524,
    "preview": "//#region Global Imports\nimport { Context, Service as MoleculerService } from 'moleculer';\nimport { Action, Method, Serv"
  },
  {
    "path": "services/index.ts",
    "chars": 100,
    "preview": "export { AttackService } from './attack.service';\nexport { PlanetService } from './planet.service';\n"
  },
  {
    "path": "services/planet.service.ts",
    "chars": 2591,
    "preview": "//#region Global Imports\nimport { Context, Service as MoleculerService } from 'moleculer';\nimport { Action, Method, Serv"
  },
  {
    "path": "src/Entities/Connection.ts",
    "chars": 386,
    "preview": "//#region Global Imports\nimport { createConnection, Connection } from 'typeorm';\n//#endregion Global Imports\n\nexport def"
  },
  {
    "path": "src/Entities/Planet.ts",
    "chars": 344,
    "preview": "//#region Global Imports\nimport { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';\n//#endregion Global Imports\n\n"
  },
  {
    "path": "src/Entities/Weapon.ts",
    "chars": 405,
    "preview": "//#region Global Imports\nimport { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';\n//#endregion Global Imports\n\n"
  },
  {
    "path": "src/Entities/index.ts",
    "chars": 70,
    "preview": "export { Planet } from './Planet';\nexport { Weapon } from './Weapon';\n"
  },
  {
    "path": "src/Interfaces/Meta/DamageMetaOutDto.d.ts",
    "chars": 81,
    "preview": "export interface DamageMetaOutDto {\n\tdamage: number;\n\tremainingShield: number;\n}\n"
  },
  {
    "path": "src/Interfaces/Meta/index.ts",
    "chars": 55,
    "preview": "export { DamageMetaOutDto } from './DamageMetaOutDto';\n"
  },
  {
    "path": "src/Interfaces/Repositories/Planet/DecreaseShieldOutDto.d.ts",
    "chars": 68,
    "preview": "export interface DecreaseShieldOutDto {\n\tremainingShield: number;\n}\n"
  },
  {
    "path": "src/Interfaces/Repositories/Planet/index.ts",
    "chars": 63,
    "preview": "export { DecreaseShieldOutDto } from './DecreaseShieldOutDto';\n"
  },
  {
    "path": "src/Interfaces/Repositories/Weapon/DecreaseAmmoOutDto.d.ts",
    "chars": 64,
    "preview": "export interface DecreaseAmmoOutDto {\n\tremainingAmmo: number;\n}\n"
  },
  {
    "path": "src/Interfaces/Repositories/Weapon/index.ts",
    "chars": 59,
    "preview": "export { DecreaseAmmoOutDto } from './DecreaseAmmoOutDto';\n"
  },
  {
    "path": "src/Interfaces/Services/Attack/IAttack.d.ts",
    "chars": 191,
    "preview": "export namespace IAttack {\n\texport interface FireInDto {\n\t\tplanetName: string;\n\t\tweaponName: string;\n\t}\n\n\texport interfa"
  },
  {
    "path": "src/Interfaces/Services/Attack/index.ts",
    "chars": 37,
    "preview": "export { IAttack } from './IAttack';\n"
  },
  {
    "path": "src/Interfaces/Services/Planet/IPlanet.d.ts",
    "chars": 188,
    "preview": "export namespace IPlanet {\n\texport interface DefendInDto {\n\t\tplanetName: string;\n\t\tweaponName: string;\n\t}\n\n\texport inter"
  },
  {
    "path": "src/Interfaces/Services/Planet/index.ts",
    "chars": 37,
    "preview": "export { IPlanet } from './IPlanet';\n"
  },
  {
    "path": "src/Interfaces/index.ts",
    "chars": 222,
    "preview": "export * from '@Interfaces/Meta';\nexport * from '@Interfaces/Repositories/Planet';\nexport * from '@Interfaces/Repositori"
  },
  {
    "path": "src/Meta/CalculateMeta.ts",
    "chars": 555,
    "preview": "//#endregion Local Imports\nimport { Planet, Weapon } from '@Entities';\n//#endregion Local Imports\n\n//#region Interface I"
  },
  {
    "path": "src/Meta/index.ts",
    "chars": 53,
    "preview": "export { CalculateMeta } from '@Meta/CalculateMeta';\n"
  },
  {
    "path": "src/Repositories/ErrorHelpers.ts",
    "chars": 283,
    "preview": "//#region Global Imports\nimport { Errors } from 'moleculer';\n//#endregion Global Imports\n\nexport const Throw404 = <R ext"
  },
  {
    "path": "src/Repositories/Planet.ts",
    "chars": 846,
    "preview": "//#region Global Imports\nimport { getManager } from 'typeorm';\n//#endregion Global Imports\n\n//#region Local Imports\nimpo"
  },
  {
    "path": "src/Repositories/Shared.ts",
    "chars": 495,
    "preview": "//#region Global Imports\nimport { getManager, ObjectType } from 'typeorm';\n//#endregion Global Imports\n\n//#region Local "
  },
  {
    "path": "src/Repositories/Weapon.ts",
    "chars": 797,
    "preview": "//#region Global Imports\nimport { getManager } from 'typeorm';\n//#endregion Global Imports\n\n//#region Local Imports\nimpo"
  },
  {
    "path": "src/Repositories/index.ts",
    "chars": 114,
    "preview": "export { WeaponRepository } from '@Repositories/Weapon';\nexport { PlanetRepository } from '@Repositories/Planet';\n"
  },
  {
    "path": "src/ServiceHelpers/AttackHelper.ts",
    "chars": 410,
    "preview": "//#region Global Imports\nimport { Context } from 'moleculer';\n//#endregion Global Imports\n\n//#region Interface Imports\ni"
  },
  {
    "path": "src/ServiceHelpers/PlanetHelper.ts",
    "chars": 418,
    "preview": "//#region Global Imports\nimport { Context } from 'moleculer';\n//#endregion Global Imports\n\n//#region Interface Imports\ni"
  },
  {
    "path": "src/ServiceHelpers/index.ts",
    "chars": 122,
    "preview": "export { AttackHelper } from '@ServiceHelpers/AttackHelper';\nexport { PlanetHelper } from '@ServiceHelpers/PlanetHelper'"
  },
  {
    "path": "swagger/config.js",
    "chars": 845,
    "preview": "const swaggerJSDoc = require('swagger-jsdoc');\n\nconst swaggerDefinition = {\n\tinfo: {\n\t\ttitle: 'Pankod MoleculerJS Boiler"
  },
  {
    "path": "swagger/index.js",
    "chars": 854,
    "preview": "const express = require('express');\nconst swaggerUi = require('swagger-ui-express');\nconst cors = require('cors');\nconst"
  },
  {
    "path": "swagger/package.json",
    "chars": 23,
    "preview": "{\n\t\"main\": \"index.js\"\n}"
  },
  {
    "path": "swagger/swagger.json",
    "chars": 2551,
    "preview": "{\n  \"info\": {\n    \"title\": \"Pankod MoleculerJS Boilerplate\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Moleculer JS Mi"
  },
  {
    "path": "swaggerConfig.json",
    "chars": 519,
    "preview": "{\n\t\"swagger\": {\n\t\t\"baseUrl\": \"./\",\n\t\t\"outputDirectory\": \"./swagger\",\n\t\t\"entryFile\": \"./services/index.ts\",\n\t\t\"host\": \"lo"
  },
  {
    "path": "test/Config/Connection.ts",
    "chars": 406,
    "preview": "//#region Global Imports\nimport { createConnection, Connection } from 'typeorm';\n//#region Global Imports\n\nexport defaul"
  },
  {
    "path": "test/Config/SetupDatabase.ts",
    "chars": 261,
    "preview": "//#region Local Imports\nimport Seeder from '../Seeder';\nimport CreateConnection from './Connection';\n//#region Local Imp"
  },
  {
    "path": "test/Config/mock.setup.ts",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "test/Integration/attack.spec.ts",
    "chars": 1278,
    "preview": "//#region Global Imports\nimport ApiGateway = require('moleculer-web');\nimport { getConnection } from 'typeorm';\nimport r"
  },
  {
    "path": "test/Integration/planet.spec.ts",
    "chars": 1218,
    "preview": "//#region Global Imports\nimport ApiGateway = require('moleculer-web');\nimport { getConnection } from 'typeorm';\nimport r"
  },
  {
    "path": "test/Seeder/AttackSeeder.ts",
    "chars": 381,
    "preview": "//#region Global Imports\nimport { getManager } from 'typeorm';\n//#endregion Global Imports\n\n//#region Local Imports\nimpo"
  },
  {
    "path": "test/Seeder/PlanetSeeder.ts",
    "chars": 366,
    "preview": "//#region Global Imports\nimport { getManager } from 'typeorm';\n//#region Global Imports\n\n//#region Local Imports\nimport "
  },
  {
    "path": "test/Seeder/index.ts",
    "chars": 264,
    "preview": "//#region Local Imports\nimport PlanetSeeder from './PlanetSeeder';\nimport AttackSeeder from './AttackSeeder';\n//#region "
  },
  {
    "path": "test/Unit/Entities/Connection.spec.ts",
    "chars": 523,
    "preview": "import CreateConnection from '../../../src/Entities/Connection';\nimport { Connection, getConnection } from 'typeorm';\n\nd"
  },
  {
    "path": "test/Unit/Meta/CalculateMeta.spec.ts",
    "chars": 1016,
    "preview": "//#region Global Imports\nimport { getManager, getConnection } from 'typeorm';\n//#endregion Global Imports\n\n//#region Loc"
  },
  {
    "path": "test/Unit/MicroServices/attack.spec.ts",
    "chars": 1358,
    "preview": "//#region Global Imports\nimport { getManager } from 'typeorm';\n//#endregion Global Imports\n\n//#region Local Imports\nimpo"
  },
  {
    "path": "test/Unit/MicroServices/planet.spec.ts",
    "chars": 1359,
    "preview": "//#region Global Imports\nimport { getManager } from 'typeorm';\n//#endregion Global Imports\n\n//#region Local Imports\nimpo"
  },
  {
    "path": "test/Unit/Repositories/ErrorHelpers.spec.ts",
    "chars": 597,
    "preview": "//#region Global Imports\nimport { Errors } from 'moleculer';\n//#endregion Global Imports\n\n//#region Local Imports\nimport"
  },
  {
    "path": "test/Unit/Repositories/Planet.spec.ts",
    "chars": 1220,
    "preview": "//#region Global Imports\nimport { getConnection } from 'typeorm';\n//#endregion Global Imports\n\n//#region Local Imports\ni"
  },
  {
    "path": "test/Unit/Repositories/Weapon.spec.ts",
    "chars": 1423,
    "preview": "//#region Global Imports\nimport { getManager, getConnection } from 'typeorm';\n//#region Global Imports\n\n//#region Local "
  },
  {
    "path": "test/Unit/ServiceHelpers/AttackHelper.spec.ts",
    "chars": 701,
    "preview": "//#region Local Imports\nimport { AttackHelper } from '@ServiceHelpers';\nimport { DummyContext } from '@Test/Utils';\n//#e"
  },
  {
    "path": "test/Unit/ServiceHelpers/PlanetHelper.spec.ts",
    "chars": 697,
    "preview": "//#region Local Imports\nimport { PlanetHelper } from '@ServiceHelpers';\nimport { DummyContext } from '@Test/Utils';\n//#r"
  },
  {
    "path": "test/Utils/BrokerHelper.ts",
    "chars": 544,
    "preview": "//#region Global Imports\nimport { ServiceBroker } from 'moleculer';\n//#endregion Global Imports\n\n/* eslint-disable */\n//"
  },
  {
    "path": "test/Utils/DummyContext.spec.ts",
    "chars": 341,
    "preview": "import { DummyContext } from './DummyContext';\nimport { Context } from 'moleculer';\n\ndescribe('Dummy Context', async () "
  },
  {
    "path": "test/Utils/DummyContext.ts",
    "chars": 548,
    "preview": "//#region Global Imports\nimport { Context, Endpoint, ServiceBroker } from 'moleculer';\n//#endregion Global Imports\n\nexpo"
  },
  {
    "path": "test/Utils/index.ts",
    "chars": 94,
    "preview": "export { DummyContext } from './DummyContext';\nexport { BrokerHelper } from './BrokerHelper';\n"
  },
  {
    "path": "tsconfig.json",
    "chars": 1170,
    "preview": "{\n\t\"compilerOptions\": {\n\t\t\"experimentalDecorators\": true,\n\t\t\"emitDecoratorMetadata\": true,\n\t\t\"esModuleInterop\": true,\n\t\t"
  },
  {
    "path": "tsconfig.production.json",
    "chars": 79,
    "preview": "{\n\t\"extends\": \"./tsconfig\",\n\t\"compilerOptions\": {\n\t\t\"baseUrl\": \"./dist\",\n\t},\n}\n"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the pankod/moleculerjs-boilerplate GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 99 files (95.4 KB), approximately 27.9k tokens, and a symbol index with 37 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!