open-index/open-npm huggingface dataset:
npm package: @qiwi/nestjs-enterprise-svc-info
Description: Service-info controller for nestjs enterprise
Latest version: 4.1.0

# @qiwi/nestjs-enterprise-svc-info
Returns uptime by `/svc-info/uptime`, application name with version by `/svc-info/version` and build info by `/svc-info/buildstamp`
## Installation
```shell script
yarn add @qiwi/nestjs-enterprise-svc-info
```
## Before using
Buildstamp is a file with build info, whose contents the module exposes by `/svc-info/buildstamp`.

Set up buidstamp forwarding into a container in your `Dockerfile`:
```dockerfile
COPY buildstamp.json $APP_DIR/buildstamp.json
``` 
Add to `"scripts"` in `package.json`:
```json
"prebuild": "<your script for generating buildstamp>",
```
We suggest using [buildstamp](https://github.com/qiwi/buildstamp).

## Usage
### Usage as module:
```typescript
import { SvcInfoModule } from '@qiwi/nestjs-enterprise-svc-info'
// ...

@Module({
  imports: [
    SvcInfoModule
    // and so on
  ],
  controllers: [ ],
  providers: [ ],
})
export class AppModule {}
```

### Usage as controller (if you need routes order):

```typescript
import { SvcInfoController } from '@qiwi/nestjs-enterprise-svc-info'

// ...

@Module({
  imports: [],
  controllers: [SvcInfoController],
  providers: [ ],
})
export class AppModule {}
```

### Setting a custom path to buildstamp file

If you want to give a custom path to your buildstamp file, import module via `register`, which accepts `ISvcInfoModuleOpts`:
```typescript
import { SvcInfoModule, ISvcInfoModuleOpts } from '@qiwi/nestjs-enterprise-svc-info'
// ...
const opts: ISvcInfoModuleOpts = {
  path: 'some/path/buildstamp.json'
}

@Module({
  imports: [
    SvcInfoModule.register(opts)
    // and so on
  ],
  controllers: [ ],
  providers: [ ],
})
export class AppModule {}
```
In case of using the module as controller: 

```typescript
import { SvcInfoController, ISvcInfoModuleOpts } from '@qiwi/nestjs-enterprise-svc-info'
// ...
const opts: ISvcInfoModuleOpts = {
  path: 'some/path/buildstamp.json'
}


@Module({
  imports: [],
  controllers: [SvcInfoController],
  providers: [
    { provide: 'ISvcInfoModuleOpts', useValue: opts }
  ],
})
export class AppModule {}
```
### [Docs](https://qiwi.github.io/nestjs-enterprise/svc-info)
npm package: @qiwi/nestjs-enterprise-thrift
Description: thrift module for nestjs enterprise
Latest version: 4.1.3

# @qiwi/nestjs-enterprise-thrift"

Nestjs module for working with [Apache Thrift](https://thrift.apache.org/)

# Installation
Requires following packages to be installed
- [@qiwi/nestjs-enterprise-logger](https://github.com/qiwi/nestjs-enterprise/tree/master/packages/logger)
- [@qiwi/nestjs-enterprise-config](https://github.com/qiwi/nestjs-enterprise/tree/master/packages/config)
- [@qiwi/nestjs-enterprise-connection-provider](https://github.com/qiwi/nestjs-enterprise/tree/master/packages/connection-provider)

```shell script
yarn add @qiwi/nestjs-enterprise-thrift
```

## Configuration
Imports
```typescript
import { Module } from '@nestjs/common'
import { ConnectionProviderModule } from '@qiwi/nestjs-enterprise-connection-provider'
import { LoggerModule } from '@qiwi/nestjs-enterprise-logger-nestjs'
import { ConsulModule } from '@qiwi/nestjs-enterprise-consul-nestjs'
import { ConfigModule } from '@qiwi/nestjs-enterprise-config-nestjs'
import { ThriftModule } from '@qiwi/nestjs-enterprise-thrift'

@Module({
  imports: [
    ConfigModule,
    LoggerModule,
    ConsulModule,
    ConnectionProviderModule,
    // and so on
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
```
## Usage
```typescript
@Injectable()
class AuthService {
  client?: Client
  creds?: TCredentials
  token?: TAuthentication

  @Inject('IConfigService')
  config: IConfig

  @Inject('IThriftClientService')
  thrift: IThriftClientService

    getClient() {
        const serviceProfile: IServiceDeclaration = this.config.get('serviceName')
        this.client = this.thrift.getClient(serviceProfile, Client, {
            multiplexer: false,
            connectionOpts: {
                transport: thrift.TBufferedTransport,
                protocol: thrift.TBinaryProtocol,
            },
        })
        return this.client
  }
}
```

## Decorators
### @ThriftServer
```typescript
    @ThriftServer(CalculatorProcessor, 9091)
    class TestServer {
      ping(result: () => void) {
        result()
      }

      add(n1: any, n2: any, result: (arg0: null, arg1: any) => void) {
        result(null, n1 + n2)
      }
    }
```

### Config
```json
{
  "data": {
    "services": {
      "service-1": {
        "type": "thrift",
        "thriftServiceName": "test service 1",
        "discovery": {
          "type": "endpoint",
          "endpoints": [{ "host": "service-1.test.com", "port": "8080" }]
        }
      },
      "service-2": {
        "type": "thrift",
        "thriftServiceName": "test service 2",
        "discovery": {
          "type": "consul",
          "serviceName": "consul name"
        },
        "creds": {
          "type": "username-and-password",
          "username": "username",
          "password": "password"
        }
      }
    }
  }
}
```

## API
### Class ConnectionProviderModule
Exports `IThriftClientService` with token `IThriftClientService`

### [Docs](https://qiwi.github.io/nestjs-enterprise/thrift/)
npm package: @qiwi/nexus-client
Description: Nexus TS client, created by Open API generator
Latest version: 1.1.5

# @qiwi/nexus-client

Nexus TS client, created by Open API generator

# Installation

```shell script
yarn add @qiwi/nexus-client
```
or
```shell script
npm i @qiwi/nexus-client
```

# Usage

```typescript
import { ComponentsApi } from '@qiwi/nexus-client'

const options = {
  auth: {
    password: 'secretPassword',
    username: 'j.sins'
  }
}

const api = new ComponentsApi({
  basePath: 'your Nexus API URL',
  baseOptions: options
})

api
  .getComponentById('bnBtLWludGVybmFsOjFjNzg3YTAzZGI4MjA5ZWI2MDUyOTU1MjUwNWFlMmNh')
  .then(d => console.log(d.data))

```
npm package: @qiwi/npm-batch-cli-api
Description: API for npm-batch CLI utilities
Latest version: 2.2.0

# @qiwi/npm-batch-cli-api
API npm-batch CLI utilities
## Installation
```shell script
npm install @qiwi/npm-batch-cli-api
yarn add @qiwi/npm-batch-cli-api
```
## Usage
```typescript
import { readConfigAndRun } from '@qiwi/npm-batch-cli-api'

readConfigAndRun({ config: 'config.json' })
    .then(() => console.log('Done.'))
```
npm package: @qiwi/npm-batch-cli-pipe
Description: CLI utility for performing batched npm actions with pipe input
Latest version: 1.4.0

# @qiwi/npm-batch-cli-pipe
The same as `@qiwi/npm-batch-cli`, but with configuring via a pipeline.
## Usage
```shell script
cat config.json | npx @qiwi/npm-batch-cli-pipe
```
See more at [@qiwi/npm-batch-cli](https://github.com/qiwi/npm-batch-action/tree/master/packages/cli) docs.
npm package: @qiwi/npm-run-all
Description: A CLI tool to run multiple npm-scripts in parallel or sequential.
Author: Toru Nagashima
Latest version: 4.1.7

## @qiwi/npm-run-parallel
Yet another one fork of [mysticatea/npm-run-all](https://github.com/mysticatea/npm-run-all), that drops some useless deps and brings deps from 2020.

## Installation
```bash
$ npm install @qiwi/npm-run-all --save-dev
$ yarn add @qiwi/npm-run-all -D 
```

## Usage
```shell script
npm-run-all clean build:*
```

Original docs → [npm-run-all.md](https://github.com/mysticatea/npm-run-all/blob/master/docs/npm-run-all.md)
npm package: @qiwi/npm-types
Description: Typescript definitions for npm registry content
Author: Chris Dickinson
Latest version: 1.0.3

# @qiwi/npm-types

The fork of [npm/types](https://github.com/npm/types) that fixes the most vulnerabilities and brings deps from 2020

Typescript definitions for npm registry content

```typescript
import * as npm from '@qiwi/npm-types';

const pkg = require('pacote');

pkg.packument('libnpm').then((obj: npm.Packument) => {
  console.log(obj.name, 'is the name of the package');
});

```

## GOAL

Make it easier for typescript users to work with npm registry content! 

![vscode tooltip screenshot](./img/tool-tip.png)

Types should have comments so documentation on npm object properties can appear in vscode contextual popups.

## types

- npm.PackageJson
    - the object in the json file you have in your project

- npm.PackageLock
    - the file generated for you by npm that pins your deps.

- npm.Packument
    - the document you get from `https://registry.npmjs.org/<package name here>`

- npm.Manifest
    - the document you get from `curl -H 'accept:application/vnd.npm.install-v1+json' https://registry.npmjs.org/<package name here>`

### subtypes


- npm.PackageVersion
    - the objects in the version fields of Packuments

- npm.LockDependency
    - how package locks describe dependencies and sub dependencies

- npm.ManifestVersion  
    - the version object in an AbbreviatedPackument

- npm.Dist
    - the object in npm.PackageVersion that holds the tarball location and checksums

- npm.NpmScripts
    - helpful object with all of the possible npm hooks

- npm.Maintainer
    - common type for author, maintainers etc used in many objects

- npm.Repository
    - string or object of repo data
npm package: @qiwi/paralint
Description: Runner to invoke ESLint in parallel
Author: Anton Golub
Latest version: 1.2.1

# paralint
> Runner to invoke ESLint in parallel

[![CI](https://github.com/qiwi/paralint/actions/workflows/ci.yaml/badge.svg?branch=master)](https://github.com/qiwi/paralint/actions/workflows/ci.yaml)
[![Maintainability](https://api.codeclimate.com/v1/badges/13f3c48486b71d4e3ca1/maintainability)](https://codeclimate.com/github/qiwi/paralint/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/13f3c48486b71d4e3ca1/test_coverage)](https://codeclimate.com/github/qiwi/paralint/test_coverage)

## Install
```shell
npm i -D paralint
```

## Usage
```shell
paralint <files and dirs> [--eslint-options] [--concurrency=4]
```

## Alternatives
* [pgAdmin/eslint-parallel](https://github.com/pgAdmin/eslint-parallel)
* [pinterest/esprint](https://github.com/pinterest/esprint)

## License 
[MIT](./LICENSE)
npm package: @qiwi/pijma-core
Description: Pijma core: assets, utils, primitives, themes, etc.
Latest version: 1.165.1

# @qiwi/pijma-core

Pijma core: assets, utils, primitives, themes, etc.

## Install
```bash
npm i --save @qiwi/pijma-core
yarn add @qiwi/pijma-core
```

## License
[MIT](../../LICENSE)
npm package: @qiwi/pijma-desktop
Description: Pijma desktop UI components.
Latest version: 1.168.1

# @qiwi/pijma-desktop

Pijma desktop UI components.

## Demo
* [@qiwi/pijma-desktop](https://qiwi.github.io/pijma/desktop)

## Install
```bash
npm i --save @qiwi/pijma-desktop
yarn add @qiwi/pijma-desktop
```

## Usage
```javascript
import React from 'react'
import {cache, themes, fonts, reset, CacheProvider, ThemeProvider, Global, Button, TextField} from '@qiwi/pijma-desktop'

export const App = () => (
  <CacheProvider value={cache}>
    <ThemeProvider theme={themes.orange}>
      <Global styles={[reset, fonts]}/>
      <Button type="submit" kind="brand" size="accent" text="Button"/>
      <TextField type="tel" name="phone" placeholder="+7 (987) 564-32-10"/>
      <TextField name="phone" mask={['(', /\d/, /\d/, /\d/, ')', /\d/, /\d/, /\d/, '-', /\d/, /\d/, '-', /\d/, /\d/]}/>
    </ThemeProvider>
  </CacheProvider>
)
```

## License
[MIT](../../LICENSE)
npm package: @qiwi/pijma-desktop-extra
Description: Pijma desktop extra UI components.
Latest version: 0.2.37

# @qiwi/pijma-desktop-extra

Pijma desktop extra UI components.

## Install
```bash
npm i --save @qiwi/pijma-desktop-extra
yarn add @qiwi/pijma-desktop-extra
```

## Usage
```javascript
import React from 'react'
import { cache, themes, fonts, reset, CacheProvider, ThemeProvider, Global } from '@qiwi/pijma-desktop'
import { Table } from '@qiwi/pijma-desktop-extra'

export const App = () => (
  <CacheProvider value={cache}>
    <ThemeProvider theme={themes.orange}>
      <Global styles={[reset, fonts]}/>
      <Table
        columns={columns}
        data={data}
        onSelect={onSelect}
      />
    </ThemeProvider>
  </CacheProvider>
)
```

## License
[MIT](../../LICENSE)
npm package: @qiwi/pijma-fonts
Description: Self-hosted pijma fonts (Museo Sans).
Latest version: 1.1.0

# @qiwi/pijma-fonts

Self-hosted pijma fonts (Museo Sans).

## Install

```bash
npm i --save @qiwi/pijma-fonts
yarn add @qiwi/pijma-fonts
```

## Usage
```javascript
import '@qiwi/pijma-fonts'
```

## License
[MIT](../../LICENSE)
npm package: @qiwi/pijma-mobile
Description: Pijma mobile UI components.
Latest version: 1.167.1

# @qiwi/pijma-mobile

Pijma mobile UI components.

## Demo
* [@qiwi/pijma-mobile](https://qiwi.github.io/pijma/mobile)

## Install
```bash
npm i --save @qiwi/pijma-mobile
yarn add @qiwi/pijma-mobile
```

## Usage
```javascript
import React from 'react'
import {cache, themes, fonts, reset, CacheProvider, ThemeProvider, Global, Button, TextField} from '@qiwi/pijma-mobile'

export const App = () => (
  <CacheProvider value={cache}>
    <ThemeProvider theme={themes.orange}>
      <Global styles={[reset, fonts]}/>
      <Button type="submit" kind="brand" size="accent" text="Button"/>
      <TextField type="tel" name="phone" placeholder="+7 (987) 564-32-10"/>
      <TextField name="phone" mask={['(', /\d/, /\d/, /\d/, ')', /\d/, /\d/, /\d/, '-', /\d/, /\d/, '-', /\d/, /\d/]}/>
    </ThemeProvider>
  </CacheProvider>
)
```

## License
[MIT](../../LICENSE)
npm package: @qiwi/pijma-ssr
Description: Pijma SSR utilities.
Latest version: 1.6.5

# @qiwi/pijma-ssr

Pijma SSR utilities.

## Install

```bash
npm i --save @qiwi/pijma-ssr
yarn add @qiwi/pijma-ssr
```

## License
[MIT](../../LICENSE)
npm package: @qiwi/polyfill-service
Description: A polyfill combinator
Latest version: 1.0.1

# Polyfill.io API
> The fork of the [Financial-Times/polyfill-service](https://github.com/Financial-Times/polyfill-service) to bring some optimizations.

## Differences
* Deps revision: only the latest version of the [polyfill-library@3](https://github.com/Financial-Times/polyfill-library) is used, so `node_modules` size is about 1/7 of the original — 471M vs 3.4G.
* Node.js 18 instead of 12
* Moved to yarn
* Ability to use ENV variables to allow access by CORS for the domain itself and subdomains
```shell
ALLOWED_DOMAINS=google.com,localhost # <-- must be first level domains
```
* Ability to switch off documentation site
```shell
SERVE_STATIC_SITE=0 # 1 || 0
```
* UPLOAD_DIR env var exposed

### Integrated bundle analyzer
```bash
curl --location --request POST 'https://polyfill.qiwi.com/__analyze' \
--form 'file=@"/bundle1.js"' \
--form 'file=@"/bundle2.js"' \
--form 'flags="always"' \
--form 'useComputeAtEdgeBackend="no"' \
--form 'hostname="polyfill.qiwi.com"' \
--form 'unknown="unknown"' \
--form 'omit="['\''setImmediate'\'']"'
```

[@qiwi/create-polyfill-service-url](https://github.com/qiwi-forks/polyfill-service-url-builder) for more options info


## License

Polyfill.io is licensed under the terms of the [MIT license](./LICENSE.md).
npm package: @qiwi/redux-signal-bus
Description: Signal bus over redux actions
Author: Anton Golub
Latest version: 1.0.3

# redux-signal-bus
[![buildStatus](https://api.travis-ci.com/qiwi/redux-signal-bus.svg?branch=master)](https://travis-ci.com/qiwi/redux-signal-bus)
[![dependencyStatus](https://img.shields.io/david/qiwi/redux-signal-bus.svg?maxAge=3600)](https://david-dm.org/qiwi/redux-signal-bus)
[![devDependencyStatus](https://img.shields.io/david/dev/qiwi/redux-signal-bus.svg?maxAge=3600)](https://david-dm.org/qiwi/redux-signal-bus)
[![Maintainability](https://api.codeclimate.com/v1/badges/3a306db9033bf8a25d73/maintainability)](https://codeclimate.com/github/qiwi/redux-signal-bus/maintainability)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com)
[![coverage](https://img.shields.io/coveralls/qiwi/redux-signal-bus.svg?maxAge=3600)](https://coveralls.io/github/qiwi/redux-signal-bus)

We'll create our own notification bus with ttl, filters, blackjack and hookers over redux.
## Install
```bash
    yarn add @qiwi/redux-signal-bus
    npm i @qiwi/redux-signal-bus
```

## Usage
##### Inject to store
Since [store.getReducer](https://github.com/reactjs/redux/issues/350) was replaced from redux, there's no tricky way to inject reducer to chain.
So you need to wrap bus instance manually in accordance to your app architecture

```javascript
    const bus = new Bus()
    const store = createStore({[bus.getScope()]: bus.getReducer(), ...})
    bus.configure({store})
```

##### Bind with component

```javascript
    class Item extends Component {
      render (props) {
        return props.bus.listen('foo')
      }
    }
    export default bus.connect(Item)
```

Don't forget to wrap your app with redux provider
```javascript
    <Provider store={store}><App/></Provider>
```
or just inject the store by hand 
```javascript
    const ItemWithBus = bus.connect(Item)
    const component = new ItemWithBus({store})
```

##### Bus API

```javascript
    export type IFilterValue = | string | RegExp | Function | any
    export interface IBus {
        scope: string;
        store: IStore;
        dispatcher: IDispatcher;
        
        constructor(): IBus;
        configure(opts: IBusOpts): IBus;
        emit(name: string, data?: ?any, ttl?: ?number, silent: ?ISilent): void;
        listen(value: IFilterValue, silent: ?ISilent, skipCompact: ?boolean): ISignalStack;
        erase(value: IFilterValue, silent: ?ISilent): ISignalStack;
        capture(value: IFilterValue, silent: ?ISilent): ISignalStack;
        connect(component: IReactComponent): IReactComponent;
        getReducer(): IReducer;
        getScope(): string;
        hashUpdate(): void
    }

```

Usage examples are placed in ./example dir. In general it looks like this:

```javascript
import bus from '../bus'
import React, {Component} from 'react'

class BarComponent extends Component {
  render(props) {
    return (<div>
      Signals from from the 'FooComponent':
      {props.bus.listen('foo').map(({data}) => JSON.stringify(data)).join(', ')}
    </div>)
  }
}

export default bus.connect(BarComponent)
```
npm package: @qiwi/repocrawler-common
Description: Common
Latest version: 1.1.0

# @qiwi/repocrawler-common
Common types & helper functions
All crawlers implement `TRepoCrawler` interface

## TRepoCrawler
### getCommit(owner: string, repo: string, ref: string): Promise<[TCommitInfo](./src/main/ts/types/crawler.ts#L6)>
Get commit by `ref` from `owner`/`repo` repository.
### getRawContent(owner: string, repo: string, path: string): Promise<string>
Get file `path` from `owner`/`repo` repository.
### fetchRepoInfo(opts: { out: string, paths?: string[], orgs?: Array<string> }): Promise<PromiseSettledResult<void>[]>
Fetch files for all repositories by list of organizations/owners. Output is a separate json-file for each repository.
- `out` - path to directory to save output files;
- `paths` - paths of files to fetch, default is [`package.json`, `yarn.lock`, `package-lock.json`, `npm-shrinkwrap.json`];
- `orgs` - list of organizations/owners, defaults to all.

If `paths` is not specified, output file format is [TRepoCrawlerReportResultItem](./src/main/ts/types/crawler.ts#L40), this can be used as input for [@qiwi/repocrawler-reporters](../reporters).
Otherwise output file format is [TRepoCrawlerResultItem](./src/main/ts/types/crawler.ts#L36).
### getRepoFiles(repo: [TRepo](./src/main/ts/types/crawler.ts#L57), paths: string[]): Promise<[TFile](./src/main/ts/types/crawler.ts#L25)[]>
Fetch files of repo `repo.org`/`repo.repo` by `paths`.
### getInfoByRepos(repo: [TRepo](./src/main/ts/types/crawler.ts#L57), paths: string[])): Promise<[TRepoCrawlerResultItem](./src/main/ts/types/crawler.ts#L36)[]>
Fetch files and last commits of given repos by `paths`
### getReportInfoByRepos(repo: [TRepo](./src/main/ts/types/crawler.ts#L57)): Promise<[TRepoCrawlerReportResultItem](./src/main/ts/types/crawler.ts#L40)[]>
Get `package.json`, `yarn.lock`, `package-lock.json`, `npm-shrinkwrap.json` and last commits if given repos. Json-files are parsed.
Output files can be used as input for [@qiwi/repocrawler-reporters](../reporters)
### commonCrawlerMethodsFactory(base: TBaseCrawler, opts: { name: string, debug?: boolean }, logger: ILogger): [TCommonCrawler](./src/main/ts/types/crawler.ts#L62)
Returns object with common crawler methods.
npm package: @qiwi/repocrawler-gerrit
Description: Crawler for Gerrit
Latest version: 1.1.0

# @qiwi/repocrawler-gerrit
Gerrit crawler
## Installation
```shell
yarn add @qiwi/repocrawler-gerrit
npm i @qiwi/repocrawler-gerrit
```
## Usage
```js
import { createGerritCrawler } from '@qiwi/repocrawler-gerrit'

const crawler = createGerritCrawler(
  {
    baseUrl: 'foo',
    auth: {
      username: 'bar',
      password: 'baz'
    }
  },
  {
    ratelimit: {
      period: 1000,
      count: 4
    }
  }
)

crawler.fetchRepoInfo({ out: 'path/to/save/data', paths: ['src/main/ts/index.ts'], orgs: ['organization1', 'organization2'] })
  .then(() => console.log('Done.'))
```
## API
See [here](../common/README.md#TRepoCrawler)
npm package: @qiwi/repocrawler-github
Description: Crawler for GitHub
Latest version: 1.1.0

# @qiwi/repocrawler-github
GitHub crawler
## Installation
```shell
yarn add @qiwi/repocrawler-github
npm i @qiwi/repocrawler-github
```
## Usage
```js
import { createGithubCrawler } from '@qiwi/repocrawler-github'

const crawler = createGithubCrawler(
  {
    baseUrl: 'foo',
    auth: 'token'
  },
  {
    ratelimit: {
      period: 1000,
      count: 4
    }
  }
)

crawler.fetchRepoInfo({ out: 'path/to/save/data', paths: ['src/main/ts/index.ts'], orgs: ['organization1', 'organization2'] })
  .then(() => console.log('Done.'))
```
## API
See [here](../common/README.md#TRepoCrawler)
npm package: @qiwi/security-context
Description: Security context utils
Author: Anton Golub
Latest version: 0.0.3

# security-context [RnD]

Basic utils for security context providing.

[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com)
[![buildStatus](https://img.shields.io/travis/qiwi/security-context.svg?maxAge=3600&branch=master)](https://travis-ci.org/qiwi/security-context)
[![coverage](https://img.shields.io/coveralls/qiwi/security-context.svg?maxAge=3600)](https://coveralls.io/github/qiwi/security-context)
[![dependencyStatus](https://img.shields.io/david/qiwi/security-context.svg?maxAge=3600)](https://david-dm.org/qiwi/security-context)
[![devDependencyStatus](https://img.shields.io/david/dev/qiwi/security-context.svg?maxAge=3600)](https://david-dm.org/qiwi/security-context)

##### Install
```bash
    npm i -S @qiwi/security-context    
```

##### Contracts
Inspired by [Spring](https://spring.io/)
* Authentication — basic auth iface
* *Token — custom auth impl
* Authority - represents an authority granted to an Authentication object.
* Role — basic authority type
* Permission — a representation of the permission object as supplied by the expression system

##### Usage concept
```javascript
    import {Role, AbstractToken, PermissionEvaluator} from '@qiwi/security-context'

    // Create role as basic Authority
    const admin = new Role('admin')
    const operator = new Role('operator')
    
    // Specify custom token logic
    class CustomToken extends AbstractToken {
      //...
    }
    
    // Configure your evaluator
    class CustomEvaluator extends PermissionEvaluator {
      constructor() {
        super()
      }
      hasPermission(token, target, permission) {
        const roles = token.authorities
        
        if (roles.contains(admin)) {
          return true
        }
        
        if (roles.contains(operator)) {
          if (permission === 'owner') {
            if (target.owner_id === token.principal.id) {
              return true
            }
          }
        }
        
        return false
      }
    }
    const evaluator = new PermissionEvaluator()
    
    // Handle auth event, build Auth instance
    const user = {
      login: 'foo'
    }
    fetch({/*...*/})
      .then(res => {
        const data = res.json()
        const token = new CustomToken(
          user,
          data.roles.map(v => new Role(v)),
          data.details
        )
        token.authenticated = true

      })
      .catch(e => {
        return new Authentication(user)
      })
      
    // Then pass auth to context and resolve permission where it's needed
    const doSomething = (target, ...args) => {
      if (evaluator.hasPermission(token, target, 'owner')) {
        // ...
      }
    }
```
npm package: @qiwi/semrel-actions
Description: Semrel actions provider
Author: Anton Golub
Latest version: 1.2.1

# @qiwi/semrel-actions
[Semrel](https://github.com/semantic-release/semantic-release) plugin for data syncing with remote workspaces

## Motivation
The main purpose of this plugin is to provide _non-blocking_ release flow (no commits, no conflicts),
but keep the benefits of stateful operations like changelog appending, docs publishing and so on.

## Usage area
* Shared build state
* Cross-release semaphore
* Build meta publishing: coverage, buildstamp 

## Status
🚧 WIP 🚧

## Install
```shell script
yarn add @qiwi/semrel-actions -D
```

## Config examples
```json
{
  "plugins": [
    ["@qiwi/semrel-actions", {
      "providers": [
        {
          "provider": "metabranch",
          "options": {
            "branch": "metabranch",
            "url": "repoUrl"
          }
        }
      ]
    }]
  ],
  "prepare": [
    ["@qiwi/semrel-actions", {
      "actions": [{
        "provider": "metabranch",
        "options": {
          "from": "<branch>-<packageName>-changelog.md",
          "to": "changelog.md"
        }
      }]
    }]
  ],
  "publish": [
    ["@qiwi/semrel-actions", {
      "actions": [{
        "provider": "metabranch",
        "options": {
          "from": ["docs/*", "coverage/*", "buildstamp.json"],
          "to": "<git>/<nextVersion>"
        }
      }, {
        "provider": "metabranch",
        "options": {
          "from": "changelog.md",
          "to": "<branch>-<packageName>-changelog.md"
        }
      }]
    }]
  ]
}
```
npm package: @qiwi/semrel-common
Description: Semrel common utils
Author: Anton Golub
Latest version: 3.5.1

# @qiwi/semrel-common
Common semrel utils: config reader, git-client, etc.

## Install
```shell script
yarn add @qiwi/semrel-common
```

## Usage
```typescript
import { gitTags } from '@qiwi/semrel-common'

const tags = await gitTags({ cwd: '/foo/bar/baz', branch: 'master' }) 
```
npm package: @qiwi/semrel-config
Description: QIWI shared semrel config
Author: Anton Golub
Latest version: 1.4.3

# @qiwi/semrel-config
Shared QIWI OSS config for [semantic-release](https://github.com/semantic-release/semantic-release)  

## Install
```shell script
yarn add @qiwi/semrel-config -D
```

## Usage
Inject this shared config in any way supported by [semrel configuration flow](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration). For example, **.releaserc**: 
```json
{
  "extends": "@qiwi/semrel-config"
}
```
npm package: @qiwi/semrel-config-monorepo
Description: QIWI shared semrel config for monorepos
Author: Anton Golub
Latest version: 1.6.5

# @qiwi/semrel-config-monorepo
Shared QIWI OSS config for [multi-semantic-release](https://github.com/qiwi/multi-semantic-release)  

## Install
```shell script
yarn add @qiwi/semrel-config-monorepo -D
```

## Usage
Inject this shared config in any way supported by [**msr** configuration flow](https://github.com/dhoulb/multi-semantic-release#configuration). 
```json
{
  "extends": "@qiwi/semrel-config--monorepo"
}
```
npm package: @qiwi/semrel-metabranch
Description: Semrel plugin for two-way data sync with remote branch
Author: Anton Golub
Latest version: 3.1.3

# @qiwi/semrel-metabranch
[Semrel](https://github.com/semantic-release/semantic-release) plugin for two-way data sync with any remote branch on any release step. 


| Step               | Description |
|--------------------|-------------|
| `verifyConditions` | Performs actions as declared in step options. |
| `analyzeCommits`   | As prev. |
| `verifyRelease`    | ... |
| `generateNotes`    | ... |
| `prepare`          | ... |
| `publish`          | ... |
| `addChannel`       | ... |
| `success`          | ... |
| `fail`             | ... |

## Install
```shell script
yarn add @qiwi/semrel-metabranch -D
```

## Usage
As a part of plugin declaration:
```json
// .release.rc
{
  "plugins": [[
    "@qiwi/semrel-multibranch",
    {
      "verify": {
        "action": "fetch",
        "branch": "metabranch",
        "from": "foo",
        "to": "bar"
      }
    }
  ]]
}
```
Action declared in release step:
```json
{
  "publish": [[
    "@qiwi/semrel-multibranch",
    {
      "action": "push",
      "branch": "metabranch",
      "from": "foo/**/*.txt",
      "to": "bar",
      "message": "commit message"
    }
  ]]
}
```

### GitHub Pages docs pushing example
```js
module.exports = {
  debug: true,
  branch: 'master',
  plugins: [
    [
      '@qiwi/semrel-metabranch',
      {
        publish: {
          action: 'push',
          branch: 'gh-pages',
          from: './docs',
          to: '.',
          message: 'update docs ${nextRelease.gitTag}'
        }
      }
    ],
    ...
  ]
}
```

### Configuration
##### Environment variables

| Variable                     | Description                                               |
|------------------------------| --------------------------------------------------------- |
| `GH_TOKEN` or `GITHUB_TOKEN` | **Required.** The token used to authenticate with GitHub. |

##### Options

| Option          | Description            | Default |
|-----------------|------------------------| --------|
| `action`        | Action to perform: `fetch`/`push` |
| `branch`        | Branch to push         | `metabranch` |
| `message`       | Commit message powered by lodash.template: `docs <%= nextRelease.gitTag %>` | `update meta` |
| `from`          | Source glob pattern    | `.` (root) |
| `to`            | Destination directory  | `.` (root) |


## API
### TActionOptions
```typescript
export type TBaseActionOptions = {
  branch: string
  from: string | string[]
  to: string
  message: string
}

export type TActionOptionsNormalized = TBaseActionOptions & {
  repo: string
  cwd: string
  temp: string
}

export type TActionType = 'fetch' | 'push'

export type TActionOptions = Partial<TActionOptionsNormalized> & {
  repo: string
}

export type TPluginOptions = Partial<TBaseActionOptions> & {
  action: TActionType
}
```

### Defaults
```typescript
export const branch = 'metabranch'
export const from = '.'
export const to = '.'
export const message = 'update meta'

export const defaults = {
  branch,
  from,
  to,
  message,
}
```

# License
MIT
npm package: @qiwi/semrel-plugin-creator
Description: Semrel plugin creator
Author: Anton Golub
Latest version: 2.4.1

# @qiwi/semrel-plugin-creator
[Semrel](https://github.com/semantic-release/semantic-release) plugin creator

## Install
```shell script
yarn add @qiwi/semrel-plugin-creator
```

## Usage
```typescript
import {createPlugin} from '@qiwi/semrel-plugin-creator'

const handler = async ({step, pluginConfig, context, name}) => {
  if (step === 'prepare') {
    pluginConfig.foo = 'bar'
  }

  if (step === 'publish') {
    await doSomething()
  }
}

const plugin = createPlugin({
  handler,
  name: 'plugin-name',
  include: ['prepare', 'publish']
})
```

## API
```typescript
export type TPluginHandlerContext = {
  pluginConfig: TPluginConfig
  stepConfig: TPluginConfig
  stepConfigs: TStepConfigs
  context: TSemrelContext
  step: TReleaseStep
}

export type TPluginFactoryOptionsNormalized = {
  handler: TReleaseHandler
  name?: string
  include: TReleaseStep[]
  exclude: TReleaseStep[]
  require: TReleaseStep[]
}

export type TPluginFactoryOptions = Partial<TPluginFactoryOptionsNormalized>

export type TReleaseHandler = (context: TPluginHandlerContext) => Promise<any>

export type TPluginFactory = (
  handler: TPluginFactoryOptions | TReleaseHandler,
) => TPlugin
```
npm package: @qiwi/semrel-preset
Description: QIWI OSS semrel plugins preset
Author: Anton Golub
Latest version: 3.1.11

# @qiwi/semrel-preset
Shared QIWI OSS plugin preset for [semantic-release](https://github.com/semantic-release/semantic-release)  
What's inside:
* [@qiwi/semantic-release-gh-pages-plugin](https://github.com/qiwi/semantic-release-gh-pages-plugin)
* [@semantic-release/commit-analyzer](https://github.com/semantic-release/commit-analyzer)
* [@semantic-release/release-notes-generator](https://github.com/semantic-release/release-notes-generator)
* [@semantic-release/changelog](https://github.com/semantic-release/changelog)
* [@semantic-release/npm](https://github.com/semantic-release/npm)
* [@semantic-release/github](https://github.com/semantic-release/github)
* [@semantic-release/git](https://github.com/semantic-release/git)
* [@semantic-release/exec](https://github.com/semantic-release/exec)

## Usage
```shell script
yarn add @qiwi/semrel-preset -D
```
npm package: @qiwi/semrel-testing-suite
Description: Semrel/msr testing helpers
Author: Anton Golub
Latest version: 3.2.1

# @qiwi/semrel-testing-suite
Semrel/msr testing helpers

## Install
```shell script
yarn add @qiwi/semrel-testing-suite -D
```

## Usage
```ts
import { resolve } from 'path'
import resolveFrom, { silent as resolveFromSilent } from 'resolve-from'
import semanticRelease from 'semantic-release'
import { 
  cleanPath,
  copyDirectory,
  gitCommitAll,
  gitInit,
  gitInitOrigin,
  gitPush
} from '@qiwi/semrel-testing-suite'
import { createPlugin } from '@qiwi/semrel-plugin-creator'

const fixtures = resolve(__dirname, '../fixtures')

describe('integration', () => {
  const handler: any = jest.fn(({step}) => {
    if (step === 'analyzeCommits') {
      return 'patch'
    }
  })
  const pluginName = 'some-plugin'
  const plugin = createPlugin({handler, name: pluginName})
  const cwd = gitInit()

  copyDirectory(`${fixtures}/yarnWorkspaces/`, cwd)
  gitCommitAll(cwd, 'feat: Initial release')
  gitInitOrigin(cwd)
  gitPush(cwd)

  beforeAll(() => {
    jest.mock(pluginName, () => plugin, {virtual: true})
    jest
      .spyOn(resolveFrom, 'silent')
      .mockImplementation((fromDir: string, moduleId: string) => {
        if (moduleId === pluginName) {
          return pluginName
        }

        return resolveFromSilent(fromDir, moduleId) as string
      })
  })

  afterAll(() => {
    jest.restoreAllMocks()
    jest.resetModules()
  })

  afterEach(jest.clearAllMocks)

  const env = {
    ...process.env,
    TRAVIS_PULL_REQUEST_BRANCH: 'master',
    TRAVIS_BRANCH: 'master'
  }

  it('plugin is compatible with semrel', async () => {
    await semanticRelease(
      {
        branches: ['master'],
        dryRun: true,
        plugins: [pluginName],
      },
      {
        cwd: cleanPath(cwd),
        env,
      },
    )

    expect(handler).toBeCalledTimes(4)
  }, 15000)
})
```
npm package: @qiwi/semrel-toolkit
Description: Semantic release tools, plugins and configs for QIWI OSS projects
Author: Anton Golub
Latest version: 3.2.13

# @qiwi/semrel-toolkit
All-in-one package to run [semantic-release](https://github.com/semantic-release/semantic-release) and [multi-semantic-release](https://github.com/qiwi/multi-semantic-release) releases with QIWI OSS plugin presets

## Usage
```shell script
npx -p @qiwi/semrel-toolkit semrel
npx -p @qiwi/semrel-toolkit multi-semrel
```
npm package: @qiwi/semrel-workspace
Description: Semrel plugin for data sync with remote workspaces
Author: Anton Golub
Latest version: 1.0.1

# @qiwi/semrel-workspace
[Semrel](https://github.com/semantic-release/semantic-release) plugin for data syncing with remote workspaces

## Motivation
The main purpose of this plugin is to provide _non-blocking_ release flow (no commits, no conflicts),
but keep the benefits of stateful operations like changelog appending, docs publishing and so on.

## Usage area
* Shared build state
* Cross-release semaphore
* Build meta publishing: coverage, buildstamp

## Status
🚧 WIP 🚧

## Install
```shell script
yarn add @qiwi/semrel-workspace -D
```

## Config examples
```json
{
  "plugins": [
    ["@qiwi/semrel-workspace", {
      "providers": [
        {
          "provider": "metabranch",
          "options": {
            "branch": "metabranch",
            "url": "repoUrl"
          }
        }
      ]
    }]
  ],
  "prepare": [
    ["@qiwi/semrel-workspace", {
      "actions": [{
        "provider": "metabranch",
        "options": {
          "from": "<branch>-<packageName>-changelog.md",
          "to": "changelog.md"
        }
      }]
    }]
  ],
  "publish": [
    ["@qiwi/semrel-workspace", {
      "actions": [{
        "provider": "metabranch",
        "options": {
          "from": ["docs/*", "coverage/*", "buildstamp.json"],
          "to": "<git>/<nextVersion>"
        }
      }, {
        "provider": "metabranch",
        "options": {
          "from": "changelog.md",
          "to": "<branch>-<packageName>-changelog.md"
        }
      }]
    }]
  ]
}
```
npm package: @qiwi/serializer
Description: Utility to serialize/deserialize js object and restore its context as close as possible
Author: Anton Golub
Latest version: 1.0.2

# @qiwi/serializer

[![Maintainability](https://api.codeclimate.com/v1/badges/7d9ced8d8d9d2ab8fc54/maintainability)](https://codeclimate.com/github/qiwi/serializer/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/7d9ced8d8d9d2ab8fc54/test_coverage)](https://codeclimate.com/github/qiwi/serializer/test_coverage)

> Utility to serialize/deserialize js object and restore its context as close as possible

## Motivation
In JS:
* We have no "classpaths", so we cannot bind class ref with its package/module.
* `JSON.serialize`, `v8.serialize` does not produce any meta that could be used to restore object context (proto, bindings).

There are just a few JSON supersets that change the situation slightly: [json-schema](https://json-schema.org/), [serialize-javascript](https://github.com/yahoo/serialize-javascript).
Therefore, yet another one incompatible format does not affect anything.

## Suggestions
* Serialized data should describe itself by meta (something like as regular file does: header + ext)
* Classes refs may be found by scanning `require.cache` inners or globals

## Status
🚧 Work in progress 🚧 / Experimental / Early preview / pre-alpha version / 0.0.0-draft

## Install
```shell script
yarn add @qiwi/serializer
```

## Usage
```typescript
import {serialize, deserialize} from '@qiwi/serializer'
import {A} from './A'

const a: A = new A()
const serialized: string = serialize(a)
const restored: A = deserialize(serialized)

console.log(restored instanceof A) // true
```

## Refs
* [https://stackoverflow.com/questions/9791925/list-of-currently-loaded-node-js-modules](https://stackoverflow.com/questions/9791925/list-of-currently-loaded-node-js-modules)
* [https://github.com/facebook/jest/issues/5120](https://github.com/facebook/jest/issues/5120)
* [https://github.com/facebook/jest/issues/5741](https://github.com/facebook/jest/issues/5741)

## License
[MIT](LICENSE)
npm package: @qiwi/sourcecrumbs
Description: Make npm provenance attestation a bit more code bound
Author: Anton Golub
Latest version: 0.0.2

# sourcecrumbs
[![Maintainability](https://api.codeclimate.com/v1/badges/b3da59ab8038c43530e6/maintainability)](https://codeclimate.com/github/qiwi/sourcecrumbs/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/b3da59ab8038c43530e6/test_coverage)](https://codeclimate.com/github/qiwi/sourcecrumbs/test_coverage)
> Make npm provenance attestation a bit more code bound

## Concept
> [The provenance attestation](https://docs.npmjs.com/generating-provenance-statements) is established by publicly providing a link to a package's source code and build instructions from the build environment. This allows developers to verify where and how your package was built before they download it.

_This allows_, so let's try to implement a working draft. Suppose we have published a package with [sourcemaps](https://sourcemaps.info/spec.html) and provenance telemetry in its [packument](https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md).
We could try:
* compare file by file pkg inners with the bound repo commit.
* match sourcemap data with the referenced git hosted sources via [sourcemap-validator](https://www.npmjs.com/package/sourcemap-validator).
* verify that pkg target (bundle, dist, whatever) corresponds its sources somehow. Hmm... This may require heuristics, unminification, AST comparison or something like that.

## Usage

```ts
import {track} from '@qiwi/sourcecrumbs'

const result = await track({
  name: 'toposource',
  version: '1.1.4',
  registry: 'https://registry.npmjs.org'
})
// →
result = {
  meta: {
    pkgRef: {
      name: 'toposource',
      version: '1.1.4',
      registry: 'https://registry.npmjs.org'
    },
    repoRef: {
      type: 'git',
      url: 'git+https://github.com/semrel-extra/toposource.git',
      hash: 'b4f56f4ce75460c670363457821c054ed4db8464',
    }
  },
  tracks: {
    'package.json': {
      source: {
        refs: ['package.json'],
        coherence: 0.9995309568480301
      },
      sourcemap: null
    },
    'target/cjs/index.js': {
      source: null,
      sourcemap: {
        refs: [
          'src/main/ts/index.ts',
          'src/main/ts/toposource.ts'
        ],
        checks: {
          valid: true
        },
        coherence: null
      }
    },
    // ...
  }
}
```

## Refs
* https://github.blog/2023-04-19-introducing-npm-package-provenance/
* https://docs.npmjs.com/generating-provenance-statements
* https://slsa.dev/provenance/v0.2
* https://www.mattzeunert.com/2016/02/14/how-do-source-maps-work.html
* https://blog.sentry.io/2018/10/18/4-reasons-why-your-source-maps-are-broken/
* https://stackoverflow.com/questions/44527036/how-can-i-check-source-map-transpiled-javascript-consistency
* https://stackoverflow.com/questions/72263693/how-can-i-assert-minified-javascript-is-equivalent-to-source
* https://sourcemaps.info/spec.html

## Licence
[MIT](./LICENSE)
npm package: @qiwi/stdstream-snapshot
Description: Util for CLI testing: fetch stdout, stderr streams and match data to snapshot
Author: Anton Golub
Latest version: 1.2.9

# @qiwi/stdstream-snapshot
[![CI](https://github.com/qiwi/stdstream-snapshot/actions/workflows/ci.yaml/badge.svg)](https://github.com/qiwi/stdstream-snapshot/actions/workflows/ci.yaml)
[![Maintainability](https://api.codeclimate.com/v1/badges/5770053f57f0656df4ea/maintainability)](https://codeclimate.com/github/qiwi/stdstream-snapshot/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/5770053f57f0656df4ea/test_coverage)](https://codeclimate.com/github/qiwi/stdstream-snapshot/test_coverage)
[![npm (scoped)](https://img.shields.io/npm/v/@qiwi/stdstream-snapshot)](https://www.npmjs.com/package/@qiwi/stdstream-snapshot)

Util for CLI testing: fetch stdout, stderr streams and match its data to snapshot

## Install
```bash
yarn add @qiwi/stdstream-snapshot -D
npm add @qiwi/stdstream-snapshot -D
```

## Snapshot
```json
{
  "stderr": "",
  "stdout": "/rules/some-rules.ts\n    2:7   error  'name'...",
  "err": {
    "signal": null,
    "code": 1,
    "killed": false
  }
}
```

## Usage
With [Jest](https://jestjs.io/):
```javascript
import {generateSnapshot} from 'stdstream-snapshot'

it('cmd output matches to snapshot', async () => {
  const cmd = 'somecmd --flag=foo -b'
  const result = await generateSnapshot({
    cmd,
  })

  expect(result).toMatchSnapshot()
})
```

With [Jasmine](https://jasmine.github.io/) or another test framework with no built-it snapshot API:
```javascript
import {matchSnapshot} from 'stdstream-snapshot'

it('cmd output matches to snapshot', async () => {
  const cmd = 'somecmd --flag=foo -b'
  const target = './test/snapshots/some-cmd-output.json'
  const result = await matchSnapshot({
    cmd,
    target,
    update: !!process.env.UPDATE_SNAPSHOT
  })

  expect(result).toBe(true)
})
```

## Options
There are several normalization steps supported out of box.

| Option               | Description                                                                | Default |
|----------------------|----------------------------------------------------------------------------|---------|
| `trim`               | Removes redundant spaces from both ends of strings                         | true    |
| `normalizePaths`     | Replaces `process.cwd()` prefix from any found paths in the output strings | true    |
| `normalizeSpaces`    | Converts tabs to double spaces                                             | true    |
| `normalizeEncoding`  | Replaces output rubbish like `[8m [10m`                                    | true    |

## License
[MIT](/LICENSE)
npm package: @qiwi/substrate
Description: Basic types and interfaces
Latest version: 2.1.0

# @qiwi/substrate
Basic types and interfaces

### Install
```bash
yarn add @qiwi/substrate --dev
npm i @qiwi/substrate -D
```

### Usage
```typescript
import { IStringMap } from '@qiwi/substrate'

const foo: IStringMap = {
  bar: 'baz',
  qux: 'quux'
} 
```
npm package: @qiwi/substrate-abstract
Description: Abstract classes
Latest version: 2.1.0

# @qiwi/substrate-abstract
Abstract classes collection.  
Typedoc: [https://qiwi.github.io/substrate/abstract/](https://qiwi.github.io/substrate/abstract/)

### Install
```bash
yarn add @qiwi/substrate-abstract -D
npm add @qiwi/substrate-abstract -D
```

### Usage
```typescript
import { AbstractError } from '@qiwi/substrate-abstract'

class CustomError extends AbstractError {
  foo: string
  constructor(args) {
    super(...args)
    
    this.foo = 'bar'
  }
}
```
npm package: @qiwi/substrate-std
Description: Standard iface implementations
Latest version: 2.1.0

# @qiwi/substrate-std
Standard iface implementations

### Install
```bash
yarn add @qiwi/substrate-std
npm i @qiwi/substrate-std
```

### Usage
```typescript
import { IStack } from '@qiwi/substrate-types'
import { Stack } from '@qiwi/substrate-std'

const foo: IStack<string> = new Stack()
```
npm package: @qiwi/substrate-types
Description: Basic types and interfaces. Typedoc: [https://qiwi.github.io/substrate/types/](https://qiwi.github.io/substrate/types/)
Latest version: 2.1.0

# @qiwi/substrate-types
Basic types and interfaces. Typedoc: [https://qiwi.github.io/substrate/types/](https://qiwi.github.io/substrate/types/)

### Install
```bash
yarn add @qiwi/substrate-types --dev
npm i @qiwi/substrate-types -D
```

### Usage
```typescript
import { IStringMap } from '@qiwi/substrate-types'

const foo: IStringMap = {
  bar: 'baz',
  qux: 'quux'
} 
```
npm package: @qiwi/travis-generator
Description: Code generator for travis api
Author: Anton Golub
Latest version: 1.3.2

# @travis-toolkit/generator
Code generator for travis-ci API V3

## Install
```shell script
yarn add @travis-toolkit/generator
```

## Usage
```javascript
import { generates } from '@travis-toolkit/generator'
await generates(
  path_to_save,
  'https://developer.travis-ci.com',
)
```
npm package: @qiwi/uniconfig
Description: All-in-one uniconfig pack
Author: Qiwi
Latest version: 3.5.16

# @qiwi/uniconfig

Legacy package: composed `uniconfig-core` & `uniconfig-plugin-json` 
## Install
```bash
  npm i @qiwi/uniconfig
  yarn add @qiwi/uniconfig
```