1.0.2 • Published 1 year ago

@osmonauts/telescope v1.0.2

Weekly downloads
-
License
SEE LICENSE IN LI...
Repository
github
Last release
1 year ago

Telescope 🔭

A "babel for the Cosmos", Telescope is a TypeScript Transpiler for Cosmos Protobufs. Telescope is used to generate libraries for Cosmos blockchains. Simply point to your protobuffer files and create developer-friendly Typescript libraries for teams to build on your blockchain.

The following blockchain libraries (generated by Telescope) are available via npm

🎥 Checkout our video playlist to learn how to use telescope!

Table of contents

Quickstart

Follow the instructions below to generate a new Typescript package that you can publish to npm.

First, install telescope:

npm install -g @osmonauts/telescope

Generate

Use the generate command to create a new package.

telescope generate
cd ./your-new-project
yarn 

Add Protobufs

If you have .proto files, simply add them to a ./proto folder.

However, if you want to get started quickly using existing protos from our registry, simply use the install command.

telescope install

It's not necessary, but you may also specify specific packages, e.g.

telescope install @protobufs/osmosis

Transpile

To create the Typescript files, run the transpile command.

telescope transpile

You should now seem some .ts files generated in ./src. These are the real source files used in your application.

Build

Finally, run install and buidl to generate the JS and types for publishing your module to npm.

yarn install
yarn buidl

Now you should have code inside of your ./src folder, ready for publshing via npm publish. Or, if you used the defaults, you can start developing and your code can be imported from ./src/codegen;

Usage

Programatic Usage

First add telescope to your devDependencies:

yarn add --dev @osmonauts/telescope

Install helpers and cosmjs dependencies listed here

import { join } from 'path';
import telescope from '@osmonauts/telescope';
import { rimrafSync as rimraf } from 'rimraf';

const protoDirs = [join(__dirname, '/../proto')];
const outPath = join(__dirname, '../src/codegen');
rimraf(outPath);

telescope({
  protoDirs,
  outPath,

  // all options are totally optional ;)
  options: {
    aminoEncoding: {
        enabled: true
    },
    lcdClients: {
        enabled: false
    },
    rpcClients: {
        enabled: false,
        camelCase: true
    },

    // you can scope options to certain packages:
    packages: {
      nebula: {
        prototypes: {
          typingsFormat: {
            useExact: false
          }
        }
      },
      akash: {
        stargateClients: {
            enabled: true;
            includeCosmosDefaultTypes: false;
        },
        prototypes: {
          typingsFormat: {
              useExact: false
          }
        }
      }
    }
  }
}).then(()=>{
  console.log('✨ all done!');
}).catch(e=>{
  console.error(e);
  process.exit(1);
})

Options

Amino Encoding

optiondescriptiondefaults
aminoEncoding.enabledgenerate amino types and amino converterstrue
aminoEncoding.casingFnset the amino-casing function for a projectsnake()
aminoEncoding.exceptionsset specific aminoType name exceptionssee code
aminoEncoding.typeUrlToAminocreate functions for aminoType name exceptionsundefined

Prototypes Options

optiondescriptiondefaults
prototypes.enabledenables the generation of proto encoding methodstrue
prototypes.includePackageVarexport a protoPackage variable to indicate package namefalse
prototypes.excluded.packagesexclude a set of packages from transpilationundefined
prototypes.excluded.protosexclude a set of proto files from transpilationundefined
prototypes.fieldDefaultIsOptionalboolean value representing default optionality of fieldfalse
prototypes.useOptionalNullableuse (gogoproto.nullable) values in determining optionalitytrue
prototypes.allowUndefinedTypesboolean value allowing Types to be undefinedfalse
prototypes.optionalQueryParamsboolean value setting queryParams to be optionalfalse
prototypes.optionalPageRequestsboolean value setting PageRequest fields to optionalfalse

Prototypes Methods

optiondescriptiondefaults
prototypes.methods.encodeboolean to enable encode method on proto objectstrue
prototypes.methods.decodeboolean to enable decode method on proto objectstrue
prototypes.methods.fromJSONboolean to enable fromJSON method on proto objectstrue
prototypes.methods.toJSONboolean to enable toJSON method on proto objectstrue
prototypes.methods.fromPartialboolean to enable fromPartial method on proto objectstrue
prototypes.methods.fromSDKboolean to enable fromSDK method on proto objectsfalse
prototypes.methods.toSDKboolean to enable toSDK method on proto objectsfalse

LCD Client Options

optiondescriptiondefaults
lcdClients.enabledgenerate LCD clients that can query proto Query messagestrue
lcdClients.bundlewill generate factory bundle aggregate of all LCD Clientstrue
lcdClients.scopedwill generate factory of scoped LCD Clientsundefined
lcdClients.scopedIsExclusivewill allow both scoped bundles and all RPC Clientstrue

See LCD Clients for more info.

RPC Client Options

optiondescriptiondefaults
rpcClients.enabledgenerate RPC clients that can interact with proto messagestrue
rpcClients.bundlewill generate factory bundle aggregate of all RPC Clientstrue
rpcClients.camelCaseuse camel-case for RPC methods when generating RPC clientstrue
rpcClients.scopedwill generate factory of scoped RPC Clientsundefined
rpcClients.scopedIsExclusivewill allow both scoped bundles and all RPC Clientstrue
rpcClients.enabledServiceswhich services to enableMsg,Query,Service

See RPC Clients for more info.

Stargate Client Options

optiondescriptiondefaults
stargateClients.includeCosmosDefaultTypesif true, will include the cosmjs defaults with stargate clientstrue (except cosmos package)

State Management

React Query

optiondescriptiondefaults
reactQuery.enabledif true, will create react hooks that use @tanstack/react-query hooksfalse

Mobx

optiondescriptiondefaults
mobx.enabledif true, will create mobx stores that use mobxfalse

Pinia

optiondescriptiondefaults
pinia.enabledif true, will create pinia stores that use piniafalse

Typings and Formating

optiondescriptiondefaults
prototypes.typingsFormat.useDeepPartialdefaults to true, but if disabled uses the Partial TS typetrue
prototypes.typingsFormat.useExactdefaults to false, but if enabled uses the Exact TS typefalse
prototypes.typingsFormat.timestampuse either date or timestamp for Timestamp proto type"date"
prototypes.typingsFormat.durationuse either duration or string for Duration proto type"duration"

Protobuf parser

optiondescriptiondefaults
prototypes.parser.keepCasepasses keepCase to protobuf parse() to keep original casingtrue
prototypes.parser.alternateCommentModepasses alternateCommentMode to protobuf parse() methodtrue
prototypes.parser.preferTrailingCommentpasses preferTrailingComment to protobuf parse() methodfalse

Typescript Disabling

optiondescriptiondefaults
tsDisable.disableAllif true, will include //@ts-nocheck on every output filefalse
tsDisable.patternsif set, will include //@ts-nocheck on matched patterns[]
tsDisable.filesif set, will include //@ts-nocheck on matched files[]

ESLint Disabling

optiondescriptiondefaults
eslintDisable.disableAllif true, will include /* eslint-disable */ on every output filefalse
eslintDisable.patternsif set, will include /* eslint-disable */ on matched patterns[]
eslintDisable.filesif set, will include /* eslint-disable */ on matched files[]

Bundle

optiondescriptiondefaults
bundle.enabledbundle all files into a scoped index filetrue

Output

optiondescriptiondefaults
removeUnusedImportsremoves unused importstrue
classesUseArrowFunctionsclasses use arrow functions instead of bind()ing in constructorsfalse
includeExternalHelpersexports a few helpers functions in extern.tsfalse

Types

Timestamp

The representation of google.protobuf.Timestamp is configurable by the prototypes.typingsFormat.timestamp option.

Protobuf typeDefault/date='date'date='timestamp'
google.protobuf.TimestampDate{ seconds: Long, nanos: number }

TODO

  • add date='string' option

Duration

The representation of google.protobuf.Duration is configurable by the prototypes.typingsFormat.duration option.

Protobuf typeDefault/duration='duration'duration='string'
google.protobuf.Duration{ seconds: Long, nanos: number }string

Composing Messages

This example shows messages from the osmojs, which was built with Telescope.

Import the osmosis object from osmojs. In this case, we're show the messages available from the osmosis.gamm.v1beta1 module:

import { osmosis } from 'osmojs';

const {
    joinPool,
    exitPool,
    exitSwapExternAmountOut,
    exitSwapShareAmountIn,
    joinSwapExternAmountIn,
    joinSwapShareAmountOut,
    swapExactAmountIn,
    swapExactAmountOut
} = osmosis.gamm.v1beta1.MessageComposer.withTypeUrl;

Now you can construct messages. If you use vscode or another typescript-enabled IDE, you should also be able to use ctrl+space to see auto-completion of the fields required for the message.

import { coin } from '@cosmjs/amino';

const msg = swapExactAmountIn({
  sender,
  routes,
  tokenIn: coin(amount, denom),
  tokenOutMinAmount
});

Calculating Fees

Make sure to create a fee object in addition to your message.

import { coins } from '@cosmjs/amino';

const fee = {
    amount: coins(0, 'uosmo'),
    gas: '250000'
}

if you are broadcasting multiple messages in a batch, you should simulate your tx and estimate the fee

import { Dec, IntPretty } from '@keplr-wallet/unit';

const gasEstimated = await stargateClient.simulate(address, msgs, memo);
const fee = {
  amount: coins(0, 'uosmo'),
  gas: new IntPretty(new Dec(gasEstimated).mul(new Dec(1.3)))
    .maxDecimals(0)
    .locale(false)
    .toString()
};

Stargate Clients

Every module gets their own signing client. This example demonstrates for the osmosis module.

Use getSigningOsmosisClient to get your SigningStargateClient, with the Osmosis proto/amino messages full-loaded. No need to manually add amino types, just require and initialize the client:

import { getSigningOsmosisClient } from 'osmojs';

const client = await getSigningOsmosisClient({
  rpcEndpoint,
  signer // OfflineSigner
});

Creating Signers

To broadcast messages, you'll want to use either keplr or an OfflineSigner from cosmjs using mnemonics.

Amino Signer

Likely you'll want to use the Amino, so unless you need proto, you should use this one:

import { getOfflineSigner as getOfflineSignerAmino } from 'cosmjs-utils';

Proto Signer

import { getOfflineSigner as getOfflineSignerProto } from 'cosmjs-utils';

WARNING: NOT RECOMMENDED TO USE PLAIN-TEXT MNEMONICS. Please take care of your security and use best practices such as AES encryption and/or methods from 12factor applications.

import { chains } from 'chain-registry';

const mnemonic =
  'unfold client turtle either pilot stock floor glow toward bullet car science';
  const chain = chains.find(({ chain_name }) => chain_name === 'osmosis');
  const signer = await getOfflineSigner({
    mnemonic,
    chain
  });

Broadcasting messages

Now that you have your client, you can broadcast messages:

import { signAndBroadcast } from '@osmosnauts/helpers';

const res = await signAndBroadcast({
  client, // SigningStargateClient
  chainId: 'osmosis-1', // use 'osmo-test-4' for testnet
  address,
  msgs: [msg],
  fee,
  memo: ''
});

LCD Clients

For querying data via REST endpoints, you can use LCD Clients. For a better developer experience, you can generate a factory of scoped bundles of all LCD Clients with the lcdClients option.

const options: TelescopeOptions = {
    lcdClients: {
        enabled: true;
    }
};

If you use the lcdClients.scoped array, you can scope to only the modules of your interest.

const options: TelescopeOptions = {
  lcdClients: {
    enabled: true,
    scoped: [
      {
        dir: 'osmosis',
        filename: 'custom-lcd-client.ts',
        packages: [
          'cosmos.bank.v1beta1',
          'cosmos.gov.v1beta1',
          'osmosis.gamm.v1beta1'
        ],
        addToBundle: true,
        methodName: 'createCustomLCDClient'
      },
      {
        dir: 'evmos',
        filename: 'custom-lcd-client.ts',
        packages: [
          'cosmos.bank.v1beta1',
          'cosmos.gov.v1beta1',
          'evmos.erc20.v1'
        ],
        addToBundle: true,
        methodName: 'createEvmosLCDClient'
      }
    ]
  }
};

This will generate a nice helper in the ClientFactory, which you can then use to query multiple modules from a single object:

import { osmosis } from './codegen';

const main = async () => {
   const client = await osmosis.ClientFactory.createLCDClient({ restEndpoint: REST_ENDPOINT });

   // now you can query the modules
   const pool = await client.osmosis.gamm.v1beta1.pool({ poolId: "1" });
   const balance = await client.cosmos.bank.v1beta1.allBalances({ address: 'osmo1addresshere' });
};

LCD Clients Classes

If you want to instantiate a single client, for any module that has a Query type, there will be a LCDQueryClient object:

import { osmosis } from "osmojs";

export const main = async () => {
    const requestClient = new LCDClient({ restEndpoint: REST_ENDPOINT });
    const client = new osmosis.gamm.v1beta1.LCDQueryClient({ requestClient });
    const pools = await client.pools();
    console.log(pools);
};

main().then(() => {
    console.log('all done')
})

RPC Clients

For querying data via RPC endpoints, you can use RPC Clients. For a better developer experience, you can generate a factory of scoped bundles of all RPC Clients with the rpcClients option.

const options: TelescopeOptions = {
  rpcClients: {
    enabled: true
  }
};

If you use the rpcClients.scoped array, you can scope to only the modules of your interest.

const options: TelescopeOptions = {
  rpcClients: {
    enabled: true,
    camelCase: true,
    scoped: [
      {
        dir: 'osmosis',
        filename: 'osmosis-rpc-client.ts',
        packages: [
          'cosmos.bank.v1beta1',
          'cosmos.gov.v1beta1',
          'osmosis.gamm.v1beta1'
        ],
        addToBundle: true,
        methodNameQuery: 'createRPCQueryClient',
        methodNameTx: 'createRPCTxClient'
      }
    ]
  }
};

This will generate helpers createRPCQueryClient and createRPCTxClient in the ClientFactory, which you can then use to query multiple modules from a single object:

import { osmosis } from './codegen';

const main = async () => {
  const client = await osmosis.ClientFactory.createRPCQueryClient({ rpcEndpoint });

  // now you can query the modules
  const pool = await client.osmosis.gamm.v1beta1.pool({ poolId: "1" });
  const balance = await client.cosmos.bank.v1beta1.allBalances({ address: 'osmo1addresshere' });
};

RPC Client Classes

If you want to instantiate a single client, you can generate RPC classes with the rpcClients option;

For any module that has a Msg, Query or Service type, a

import { osmosis, cosmos } from 'osmojs';

const MsgClient = osmosis.gamm.v1beta1.MsgClientImpl;
const QueryClient = osmosis.gamm.v1beta1.QueryClientImpl;
const ServiceClient = cosmos.base.tendermint.v1beta1.ServiceClientImpl;

Here is an example of making a query if you want to use the RPC client classes manually:

import { osmosis } from "osmojs";
import { createProtobufRpcClient, QueryClient } from "@cosmjs/stargate";
import { Tendermint34Client } from "@cosmjs/tendermint-rpc";

export const main = async () => {
    const tmClient = await Tendermint34Client.connect(RPC_ENDPOINT);
    const QueryClientImpl = osmosis.gamm.v1beta1.QueryClientImpl;
    const client = new QueryClient(tmClient);
    const rpc = createProtobufRpcClient(client);
    const queryService = new QueryClientImpl(rpc);
    const pools = await queryService.pools({})
    console.log(pools);
};

main().then(() => {
    console.log('all done')
})

Manually registering types

This example is with osmosis module in osmojs, but it is the same pattern for any module.

NOTE: this is using @cosmjs/stargate@0.28.4

import {
    AminoTypes,
    SigningStargateClient
} from '@cosmjs/stargate';
import { Registry } from '@cosmjs/proto-signing';
import { defaultRegistryTypes } from '@cosmjs/stargate';
import { OfflineSigner } from '@cosmjs/proto-signing'
import { osmosis } from 'osmojs';

export const getCustomSigningClient = async ({ rpcEndpoint, signer }: { rpcEndpoint: string, signer: OfflineSigner }) => {
  // registry
  const registry = new Registry(defaultRegistryTypes);

  // aminotypes
  const aminoTypes = new AminoTypes({
    ...osmosis.gamm.v1beta1.AminoConverter,
    ...osmosis.lockup.AminoConverter,
    ...osmosis.superfluid.AminoConverter
  });

  // load the 
  osmosis.gamm.v1beta1.load(registry);
  osmosis.lockup.load(registry);
  osmosis.superfluid.load(registry);

  const client = await SigningStargateClient.connectWithSigner(
    rpcEndpoint,
    signer,
    { registry, aminoTypes }
  );

  return client;
};

CosmWasm

Generate TypeScript SDKs for your CosmWasm smart contracts by using the cosmwasm option on TelescopeOptions. The cosmwasm option is actually a direct reference to the TSBuilderInput object, for the most up-to-date documentation, visit @cosmwasm/ts-codegen.

import { TSBuilderInput } from '@cosmwasm/ts-codegen';
const options: TelescopeOptions = {
  cosmwasm: { 
    contracts: [
      {
        name: 'SG721',
        dir: './path/to/sg721/schema'
      },
      {
        name: 'Minter',
        dir: './path/to/Minter/schema'
      }
    ],
    outPath: './path/to/code/src/'
  }
};

Dependencies

If you don't use the boilerplate, you will need to manually install

  • @cosmjs/amino
  • @cosmjs/proto-signing
  • @cosmjs/stargate
  • @cosmjs/tendermint-rpc
yarn add @cosmjs/amino @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc

If you use the LCD Client generation, you'll need to add

  • @osmonauts/lcd
yarn add @osmonauts/lcd

Troubleshooting

Create React App

CRA requires that you update Webpack configurations:

https://github.com/cosmos/cosmjs/blob/656e02374898afe755e980e93390591b4b65fd86/README.md#webpack-configs

Here is an example of a config-overrides.js:

https://github.com/pyramation/osmosis-ui/blob/main/config-overrides.js

Babel

This should not be an issue, but if you experience problems with syntax or are not using preset-env, you may need these babel plugins:

Developing

See our documentation for how to contribute and develop Telescope.

Sponsors

Kudos to our sponsors:

  • Osmosis funded the creation of Telescope.

Related

Checkout these related projects:

Credits

🛠 Built by Cosmology — if you like our tools, please consider delegating to our validator ⚛️

Thanks to these engineers, teams and projects for inspiring Telescope:

Disclaimer

AS DESCRIBED IN THE TELESCOPE LICENSES, THE SOFTWARE IS PROVIDED “AS IS”, AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.

No developer or entity involved in creating Telescope will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Telescope code or Telescope CLI, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.

0.101.2

1 year ago

0.101.3

1 year ago

0.101.5

1 year ago

0.101.0

1 year ago

0.101.1

1 year ago

0.99.1

1 year ago

0.99.2

1 year ago

0.99.12

1 year ago

0.99.10

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago

0.99.0

1 year ago

0.94.1

2 years ago

0.97.0

1 year ago

0.98.0

1 year ago

0.95.0

1 year ago

0.96.0

1 year ago

0.93.0

2 years ago

0.94.0

2 years ago

0.91.0

2 years ago

0.88.3

2 years ago

0.92.0

2 years ago

0.92.1

2 years ago

0.92.2

2 years ago

0.89.0

2 years ago

0.90.0

2 years ago

0.87.0

2 years ago

0.88.0

2 years ago

0.88.1

2 years ago

0.88.2

2 years ago

0.86.0

2 years ago

0.87.1

2 years ago

0.87.2

2 years ago

0.87.3

2 years ago

0.81.3

2 years ago

0.81.4

2 years ago

0.81.5

2 years ago

0.81.0

2 years ago

0.81.1

2 years ago

0.81.2

2 years ago

0.82.0

2 years ago

0.80.0-rc.1

2 years ago

0.85.0

2 years ago

0.85.1

2 years ago

0.83.0

2 years ago

0.84.0

2 years ago

0.78.0

2 years ago

0.79.0

2 years ago

0.76.0

2 years ago

0.80.0

2 years ago

0.77.1

2 years ago

0.77.0

2 years ago

0.77.2

2 years ago

0.74.0

2 years ago

0.75.1

2 years ago

0.75.0

2 years ago

0.43.0

2 years ago

0.55.0

2 years ago

0.70.0

2 years ago

0.67.0

2 years ago

0.44.0

2 years ago

0.67.1

2 years ago

0.33.2

2 years ago

0.33.1

2 years ago

0.56.0

2 years ago

0.71.0

2 years ago

0.68.0

2 years ago

0.45.0

2 years ago

0.64.0

2 years ago

0.41.0

2 years ago

0.38.2

2 years ago

0.38.1

2 years ago

0.38.0

2 years ago

0.53.0

2 years ago

0.65.0

2 years ago

0.39.0

2 years ago

0.54.0

2 years ago

0.66.1

2 years ago

0.66.0

2 years ago

0.43.1

2 years ago

0.66.2

2 years ago

0.62.0

2 years ago

0.36.4

2 years ago

0.36.3

2 years ago

0.59.0

2 years ago

0.36.2

2 years ago

0.36.1

2 years ago

0.36.0

2 years ago

0.36.7

2 years ago

0.36.6

2 years ago

0.36.5

2 years ago

0.48.0

2 years ago

0.63.0

2 years ago

0.40.0

2 years ago

0.37.1

2 years ago

0.37.0

2 years ago

0.52.0

2 years ago

0.60.0

2 years ago

0.57.0

2 years ago

0.34.0

2 years ago

0.72.0

2 years ago

0.46.0

2 years ago

0.69.0

2 years ago

0.61.0

2 years ago

0.35.1

2 years ago

0.58.0

2 years ago

0.35.0

2 years ago

0.73.1

2 years ago

0.73.0

2 years ago

0.50.0

2 years ago

0.47.0

2 years ago

0.20.1

2 years ago

0.20.0

2 years ago

0.17.0

2 years ago

0.17.1

2 years ago

0.32.0

2 years ago

0.29.0

2 years ago

0.25.3

2 years ago

0.25.2

2 years ago

0.25.1

2 years ago

0.21.5

2 years ago

0.25.0

2 years ago

0.21.4

2 years ago

0.21.3

2 years ago

0.21.2

2 years ago

0.21.1

2 years ago

0.21.0

2 years ago

0.18.9

2 years ago

0.18.1

2 years ago

0.18.2

2 years ago

0.18.3

2 years ago

0.18.4

2 years ago

0.18.5

2 years ago

0.18.6

2 years ago

0.18.7

2 years ago

0.33.0

2 years ago

0.18.8

2 years ago

0.14.0

2 years ago

0.14.1

2 years ago

0.14.2

2 years ago

0.18.0

2 years ago

0.26.3

2 years ago

0.26.2

2 years ago

0.26.1

2 years ago

0.26.0

2 years ago

0.22.2

2 years ago

0.22.1

2 years ago

0.22.0

2 years ago

0.18.10

2 years ago

0.19.0

2 years ago

0.15.0

2 years ago

0.15.1

2 years ago

0.15.2

2 years ago

0.30.0

2 years ago

0.27.0

2 years ago

0.23.0

2 years ago

0.12.0

2 years ago

0.12.1

2 years ago

0.16.0

2 years ago

0.16.1

2 years ago

0.11.10

2 years ago

0.31.0

2 years ago

0.28.0

2 years ago

0.24.2

2 years ago

0.24.1

2 years ago

0.24.0

2 years ago

0.11.11

2 years ago

0.11.12

2 years ago

0.4.42

2 years ago

0.8.8

2 years ago

0.4.43

2 years ago

0.4.40

2 years ago

0.4.41

2 years ago

0.8.5

2 years ago

0.8.4

2 years ago

0.8.7

2 years ago

0.8.6

2 years ago

0.4.46

2 years ago

0.4.44

2 years ago

0.4.45

2 years ago

0.7.2

2 years ago

0.7.1

2 years ago

0.7.0

2 years ago

0.9.3

2 years ago

0.10.1

2 years ago

0.10.2

2 years ago

0.10.0

2 years ago

0.8.1

2 years ago

0.8.0

2 years ago

0.8.3

2 years ago

0.8.2

2 years ago

0.11.8

2 years ago

0.11.9

2 years ago

0.11.0

2 years ago

0.11.1

2 years ago

0.11.2

2 years ago

0.11.3

2 years ago

0.11.4

2 years ago

0.11.5

2 years ago

0.11.6

2 years ago

0.11.7

2 years ago

0.9.0

2 years ago

0.9.2

2 years ago

0.9.1

2 years ago

0.5.0

2 years ago

0.5.2

2 years ago

0.5.1

2 years ago

0.6.2

2 years ago

0.6.1

2 years ago

0.6.0

2 years ago

0.4.9

3 years ago

0.4.8

3 years ago

0.4.31

2 years ago

0.4.32

2 years ago

0.4.30

2 years ago

0.4.39

2 years ago

0.4.37

2 years ago

0.4.38

2 years ago

0.4.35

2 years ago

0.4.36

2 years ago

0.4.33

2 years ago

0.4.34

2 years ago

0.4.20

3 years ago

0.4.21

3 years ago

0.4.28

2 years ago

0.4.29

2 years ago

0.4.26

2 years ago

0.4.27

2 years ago

0.4.24

2 years ago

0.4.25

2 years ago

0.4.22

2 years ago

0.4.23

2 years ago

0.4.19

3 years ago

0.4.10

3 years ago

0.4.17

3 years ago

0.4.18

3 years ago

0.4.15

3 years ago

0.4.16

3 years ago

0.4.13

3 years ago

0.4.14

3 years ago

0.4.11

3 years ago

0.4.12

3 years ago

0.4.5

3 years ago

0.4.4

3 years ago

0.4.7

3 years ago

0.4.6

3 years ago

0.4.1

3 years ago

0.4.0

3 years ago

0.4.3

3 years ago

0.4.2

3 years ago

0.3.0

3 years ago

0.2.2

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.1.10

3 years ago

0.1.9

3 years ago

0.1.8

3 years ago

0.1.7

3 years ago

0.1.6

3 years ago

0.1.5

3 years ago

0.1.4

3 years ago

0.1.3

3 years ago

0.1.2

3 years ago

0.1.1

3 years ago