# Intro

In this section we will cover the JS SDK in-depth.

# FluencePeer class

The overall workflow with the `FluencePeer` is the following:

1. Create an instance of the peer
2. Initializing the peer
3. Using the peer in the application
4. Uninitializing the peer

To create a new peer simple instantiate the `FluencePeer` class:

```typescript
const peer = new FluencePeer();
```

The constructor simply creates a new object and does not initialize any workflow. The `init` function starts the Aqua VM, initializes the default call service handlers and (optionally) connect to the Fluence network. The function takes an optional object specifying additonal peer configuration. On option you will be using a lot is `connectTo`. It tells the peer to connect to a relay. For example:

```typescript
await peer.init({
  connectTo: krasnodar[0],
});
```

connects the first node of the Kranodar network. You can find the officially maintained list networks in the `@fluencelabs/fluence-network-environment` package. The full list of supported options is described in the [API reference](js-sdk/6_reference/modules.md)

Most of the time a single peer is enough for the whole application. For these use cases`FluncePeer` class contains the default instance which can be accessed with the corresponding property:

```typescript
await FluencePeer.default.init();
```

The peer by itself does not do any useful work. You should take advantage of functions generated by the Aqua compiler. You can use them both with a single peer or in muliple peers scenario. If you are using the default peer for your application you don't need to explicitly pass it: the compiled functions will use the `default` instance in that case (see "Using multiple peers in one applicaton")

To uninitialize the peer simply call `uninit` method. It will disconnect from the network and stop the Aqua vm,

```typescript
await peer.unint();
```

# Using multiple peers in one applicaton

In most cases using a single peer is enough. However sometimes you might need to run multiple peers inside the same JS environment. When using a single peer you should initialize the `FluencePeer.default` and call Aqua compiler-generated functions without passing any peer. For example:

```typescript
import { FluencePeer } from "@fluencelabs/fluence";
import {
  registerSomeService,
  someCallableFunction,
} from "./_aqua/someFunction";

async function main() {
  await FluencePeer.default.init({
    connectTo: relay,
  });

  // ... more application logic

  registerSomeService({
    handler: async (str) => {
      console.log(str);
    },
  });

  await someCallableFunction(arg1, arg2, arg3);

  await FluencePeer.default.uninit();
}

// ... more application logic
```

If your application needs several peers, you should create a separate `FluncePeer` instance for each of them. The generated functions accept the peer as the first argument. For example:

```typescript
import { FluencePeer } from "@fluencelabs/fluence";
import {
  registerSomeService,
  someCallableFunction,
} from "./_aqua/someFunction";

async function main() {
  const peer1 = new FluencePeer();
  const peer2 = new FluencePeer();

  // Don't forget to initialize peers
  await peer1.init({
    connectTo: relay,
  });
  await peer2.init({
    connectTo: relay,
  });

  // ... more application logic

  //        Pass the peer as the first agument
  //                   ||
  //                   \/
  registerSomeService(peer1, {
    handler: async (str) => {
      console.log("Called service on peer 1: " str);
    },
  });

  //        Pass the peer as the first agument
  //                   ||
  //                   \/
  registerSomeService(peer2, {
    handler: async (str) => {
      console.log("Called service on peer 2: " str);
    },
  });

  //                Pass the peer as the first agument
  //                           ||
  //                           \/
  await someCallableFunction(peer1, arg1, arg2, arg3);


  await peer1.uninit();
  await peer2.uninit();
}

// ... more application logic
```

It is possible to combine usage of the default peer with another one. Pay close attention to which peer you are calling the functions against.

```typescript
  // Registering handler for the default peer
  registerSomeService({
    handler: async (str) => {
      console.log("Called agains the default peer: " str);
    },
  });

  //            Pay close attention to this
  //                       ||
  //                       \/
  registerSomeService(someOthePeer, {
    handler: async (str) => {
      console.log("Called against the peer named someOtherPeer: " str);
    },
  });
```

# Understanding the Aqua compiler output

Aqua compiler emits TypeScript or JavaScript which in turn can be called from a js-based environemt. The compiler outputs code for the following entities:

1. Exported `func` declarations are turned into callable async functioks
2. Exported `service` declarations are turned into functions which register callback handler in a typed manner
3. For every exported `service` the compiler generated it's interface under the name `{serviceName}Def`

## Function definitions

For every exported function definition in aqua the compiler generated two overloads. One accepting the `FluencePeer` instance as the first argument, and one without it. Otherwise arguments are the same and correspond to the arguments of aqua functions. The last argument is always an optional config object with the following properties:

- `ttl`: Optional parameter which specify TTL (time to live) of particle with execution logic for the function

The return type is always a promise of the aqua function return type. If the function does not return anything, the return type will be `Promise<void>`.

Consider the following example:

```
func myFunc(arg0: string, arg1: string):
    -- implementation

```

The compiler will generate the following overloads:

```typescript
export async function myFunc(
  arg0: string,
  arg1: string,
  config?: { ttl?: number }
): Promise<void>;

export async function callMeBack(
  peer: FluencePeer,
  arg0: string,
  arg1: string,
  config?: { ttl?: number }
): Promise<void>;
```

## Service definitions

For every exported `service` declaration the compiler will generate two entities: service interface under the name `{serviceName}Def` and a function named `register{serviceName}` with several overloads. First let's describe the most complete one using the following example:

```typescript
export interface ServiceNameDef {
  //... service function definitions
}

export function registerStringExtra(
  peer: FluencePeer,
  serviceId: string,
  service: ServiceNameDef
): void;
```

- `peer` - the Fluence Peer instance where the handler should be registered. The peer can be ommited. In that case the `FluencePeer.default` will be used instead
- `serviceId` - the name of the service id. If the service was defined with the default service id in aqua code, this argument can be ommited.
- `service` - the handler for the service.

Depending on whether or not the services was defined with the default id the number of overloads will be different. In the case it **is defined**, there would be four overloads:

```typescript
// (1)
export function registerStringExtra(
  //
  service: ServiceNameDef
): void;

// (2)
export function registerStringExtra(
  serviceId: string,
  service: ServiceNameDef
): void;

// (3)
export function registerStringExtra(
  peer: FluencePeer,
  service: ServiceNameDef
): void;

// (4)
export function registerStringExtra(
  peer: FluencePeer,
  serviceId: string,
  service: ServiceNameDef
): void;
```

1. Uses `FluencePeer.default` and the default id taken from aqua definition
2. Uses `FluencePeer.default` and specifies the service id explicitly
3. The default id is taken from aqua definition. The peer is specified explicitly
4. Specifying both peer and the service id.

If the default id **is not defined** in aqua code the overloads will exclude ones without service id:

```typescript
// (1)
export function registerStringExtra(
  serviceId: string,
  service: ServiceNameDef
): void;

// (2)
export function registerStringExtra(
  peer: FluencePeer,
  serviceId: string,
  service: ServiceNameDef
): void;
```

1. Uses `FluencePeer.default` and specifies the service id explicitly
2. Specifying both peer and the service id.

## Service interface

The service interface type follows closely the definition in aqua code. It has the form of the object which keys correspond to the names of service members and the values are functions of the type translated from aqua definition (see Type convertion). For example, for the following aqua definition:

```
service Calc("calc"):
    add(n: f32)
    subtract(n: f32)
    multiply(n: f32)
    divide(n: f32)
    reset()
    getResult() -> f32
```

The typescript interface will be:

```typescript
export interface CalcDef {
  add: (n: number, callParams: CallParams<"n">) => void;
  subtract: (n: number, callParams: CallParams<"n">) => void;
  multiply: (n: number, callParams: CallParams<"n">) => void;
  divide: (n: number, callParams: CallParams<"n">) => void;
  reset: (callParams: CallParams<null>) => void;
  getResult: (callParams: CallParams<null>) => number;
}
```

`CallParams` will be described later in the section

## Type convertion

Basic types convertion is pretty much straightforward:

- `string` is converted to `string` in typescript
- `bool` is converted to `boolean` in typescript
- All number types (`u8`, `u16`, `u32`, `u64`, `s8`, `s16`, `s32`, `s64`, `f32`, `f64`) are converted to `number` in typescript

Arrow types translate to functions in typescript which have their arguments translated to typescript types. In addition to arguments defined in aqua, typescript counterparts have an additional argument for call params. For the majority of use cases this parameter is not needed and can be ommited.

The type convertion works the same way for `service` and `func` definitions. For example a `func` with a callback might look like this:

```
func callMeBack(callback: string, i32 -> ()):
    callback("hello, world", 42)
```

The type for `callback` argument will be:

```typescript
callback: (arg0: string, arg1: number, callParams: CallParams<'arg0' | 'arg1'>) => void,
```

For the service definitions arguments are named (see calc example above)

## Call params and tetraplets

Each service call is accompanied by additional information specific to Fluence Protocol. Including `initPeerId` - the peer which initiated the particle execution, particle signature and most importantly security tetraplets. All this data is contained inside the last `callParams` argument in every generated function definition. These data is passed to the handler on each function call can be used in the application.

Tetraplets have the form of:

```typescript
{
  argName0: SecurityTetraplet[],
  argName1: SecurityTetraplet[],
  // ...
}
```

To learn more about tetraplets and application security see [Security](knowledge_security.md)

To see full specification of `CallParms` type see [Api reference](js-sdk/6_reference/modules.md)
