Compare commits
62 Commits
Author | SHA1 | Date | |
---|---|---|---|
f7f009e0d4 | |||
e5111f0433 | |||
554a7d9647 | |||
76d30b7618 | |||
eee90810da | |||
5bf7d19bf7 | |||
2fa6da38c6 | |||
e11157fe44 | |||
28d99ecb77 | |||
d8f409c191 | |||
bcfa3be58b | |||
15744d3c4e | |||
8b2f541150 | |||
b52bb4b474 | |||
42f5d66fc4 | |||
54bb9549a1 | |||
95c3314400 | |||
695d047200 | |||
c308589d28 | |||
068177b09d | |||
4a299cf3cb | |||
e5c37b1801 | |||
5be0586790 | |||
f5e5297d47 | |||
718fada493 | |||
a42b1b48b5 | |||
5ec50975f3 | |||
ad222abb6a | |||
b29e13b162 | |||
9544823401 | |||
260f000304 | |||
d8044507ed | |||
b9380be999 | |||
1b9c354d69 | |||
a8f4ecf98f | |||
6350088d2a | |||
10ef1d0455 | |||
f709238e50 | |||
49940635d5 | |||
ec4121cbcf | |||
ea9a2572f9 | |||
cc0f1c40a6 | |||
9da04081e4 | |||
4ae0925043 | |||
4e862e784b | |||
cf8abfd4f0 | |||
93c4488b9b | |||
39493465c6 | |||
cab696e45b | |||
67682892ae | |||
5c13987686 | |||
97841e0973 | |||
c8ccde9d84 | |||
654a4c6b54 | |||
12b8793c19 | |||
24e861e5b4 | |||
c7d2b2c031 | |||
f08713bb45 | |||
ad0fa8c65a | |||
88a9bfc20d | |||
0248d6f253 | |||
8d1b302e70 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -15,8 +15,6 @@ node_modules/
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_web/
|
||||
dist_serve/
|
||||
dist_ts_web/
|
||||
dist_*/
|
||||
|
||||
# custom
|
106
.gitlab-ci.yml
106
.gitlab-ci.yml
@ -3,14 +3,17 @@ image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .npmci_cache/
|
||||
key: "$CI_BUILD_STAGE"
|
||||
- .npmci_cache/
|
||||
key: '$CI_BUILD_STAGE'
|
||||
|
||||
stages:
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
|
||||
before_script:
|
||||
- npm install -g @shipzone/npmci
|
||||
|
||||
# ====================
|
||||
# security stage
|
||||
@ -18,21 +21,37 @@ stages:
|
||||
mirror:
|
||||
stage: security
|
||||
script:
|
||||
- npmci git mirror
|
||||
- npmci git mirror
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
snyk:
|
||||
auditProductionDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install -g snyk
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command snyk test
|
||||
- npmci command npm install --production --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=prod --production
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
auditDevDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=dev
|
||||
tags:
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
# ====================
|
||||
# test stage
|
||||
@ -41,37 +60,36 @@ snyk:
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
- priv
|
||||
- docker
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install lts
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- docker
|
||||
|
||||
release:
|
||||
stage: release
|
||||
script:
|
||||
- npmci node install lts
|
||||
- npmci npm publish
|
||||
- npmci node install stable
|
||||
- npmci npm publish
|
||||
only:
|
||||
- tags
|
||||
- tags
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
# ====================
|
||||
# metadata stage
|
||||
@ -79,35 +97,39 @@ release:
|
||||
codequality:
|
||||
stage: metadata
|
||||
allow_failure: true
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
- npmci command npm install -g tslint typescript
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
|
||||
tags:
|
||||
- docker
|
||||
- priv
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
trigger:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci trigger
|
||||
- npmci trigger
|
||||
only:
|
||||
- tags
|
||||
- tags
|
||||
tags:
|
||||
- docker
|
||||
- notpriv
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
pages:
|
||||
image: hosttoday/ht-docker-dbase:npmci
|
||||
services:
|
||||
- docker:stable-dind
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci node install lts
|
||||
- npmci command npm install -g @gitzone/tsdoc
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command tsdoc
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
only:
|
||||
@ -115,5 +137,5 @@ pages:
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
- public
|
||||
- public
|
||||
allow_failure: true
|
||||
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["/npmextra.json"],
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"npmci": {
|
||||
"type": "object",
|
||||
"description": "settings for npmci"
|
||||
},
|
||||
"gitzone": {
|
||||
"type": "object",
|
||||
"description": "settings for gitzone",
|
||||
"properties": {
|
||||
"projectType": {
|
||||
"type": "string",
|
||||
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
23
license
Normal file
23
license
Normal file
@ -0,0 +1,23 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Lossless GmbH
|
||||
Copyright (c) 2020 Tomás Arias
|
||||
|
||||
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.
|
||||
|
@ -4,13 +4,29 @@
|
||||
"npmAccessLevel": "public"
|
||||
},
|
||||
"gitzone": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "pushrocks",
|
||||
"githost": "code.foss.global",
|
||||
"gitscope": "push.rocks",
|
||||
"gitrepo": "smartnetwork",
|
||||
"shortDescription": "network diagnostics",
|
||||
"npmPackagename": "@pushrocks/smartnetwork",
|
||||
"license": "MIT"
|
||||
"description": "A toolkit for network diagnostics including speed tests, port availability checks, and more.",
|
||||
"npmPackagename": "@push.rocks/smartnetwork",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"network diagnostics",
|
||||
"ping",
|
||||
"port check",
|
||||
"speed test",
|
||||
"network interface",
|
||||
"public IP retrieval",
|
||||
"Cloudflare speed test",
|
||||
"network performance",
|
||||
"network utility",
|
||||
"TypeScript"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tsdoc": {
|
||||
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||
}
|
||||
}
|
2063
package-lock.json
generated
2063
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
75
package.json
75
package.json
@ -1,41 +1,64 @@
|
||||
{
|
||||
"name": "@pushrocks/smartnetwork",
|
||||
"version": "1.1.12",
|
||||
"name": "@push.rocks/smartnetwork",
|
||||
"version": "3.0.2",
|
||||
"private": false,
|
||||
"description": "network diagnostics",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"description": "A toolkit for network diagnostics including speed tests, port availability checks, and more.",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"type": "module",
|
||||
"author": "Lossless GmbH",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "(tstest test/)",
|
||||
"build": "(tsbuild)"
|
||||
"build": "(tsbuild --web --allowimplicitany)"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gitzone/tsbuild": "^2.1.17",
|
||||
"@gitzone/tstest": "^1.0.24",
|
||||
"@pushrocks/tapbundle": "^3.0.13",
|
||||
"tslint": "^5.19.0",
|
||||
"tslint-config-prettier": "^1.18.0"
|
||||
"@gitzone/tsbuild": "^2.1.61",
|
||||
"@gitzone/tsrun": "^1.2.39",
|
||||
"@gitzone/tstest": "^1.0.69",
|
||||
"@pushrocks/smartenv": "^5.0.0",
|
||||
"@pushrocks/tapbundle": "^5.0.3",
|
||||
"@types/node": "^18.11.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pushrocks/smartpromise": "^3.0.2",
|
||||
"@pushrocks/smartstring": "^3.0.10",
|
||||
"@types/default-gateway": "^3.0.0",
|
||||
"@types/portscanner": "^2.1.0",
|
||||
"default-gateway": "^5.0.3",
|
||||
"portscanner": "^2.2.0",
|
||||
"speedtest-net": "^1.5.1"
|
||||
"@pushrocks/smartping": "^1.0.7",
|
||||
"@pushrocks/smartpromise": "^3.1.7",
|
||||
"@pushrocks/smartstring": "^4.0.2",
|
||||
"@types/default-gateway": "^3.0.1",
|
||||
"isopen": "^1.3.0",
|
||||
"public-ip": "^6.0.1",
|
||||
"systeminformation": "^5.11.9"
|
||||
},
|
||||
"files": [
|
||||
"ts/*",
|
||||
"ts_web/*",
|
||||
"dist/*",
|
||||
"dist_web/*",
|
||||
"dist_ts_web/*",
|
||||
"assets/*",
|
||||
"ts/**/*",
|
||||
"ts_web/**/*",
|
||||
"dist/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts/**/*",
|
||||
"dist_ts_web/**/*",
|
||||
"assets/**/*",
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
],
|
||||
"keywords": [
|
||||
"network diagnostics",
|
||||
"ping",
|
||||
"port check",
|
||||
"speed test",
|
||||
"network interface",
|
||||
"public IP retrieval",
|
||||
"Cloudflare speed test",
|
||||
"network performance",
|
||||
"network utility",
|
||||
"TypeScript"
|
||||
],
|
||||
"homepage": "https://code.foss.global/push.rocks/smartnetwork",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://code.foss.global/push.rocks/smartnetwork.git"
|
||||
}
|
||||
}
|
4516
pnpm-lock.yaml
generated
Normal file
4516
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
1
readme.hints.md
Normal file
1
readme.hints.md
Normal file
@ -0,0 +1 @@
|
||||
|
173
readme.md
173
readme.md
@ -1,46 +1,149 @@
|
||||
# @pushrocks/smartnetwork
|
||||
# @push.rocks/smartnetwork
|
||||
network diagnostics
|
||||
|
||||
## Availabililty and Links
|
||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartnetwork)
|
||||
* [gitlab.com (source)](https://gitlab.com/pushrocks/smartnetwork)
|
||||
* [github.com (source mirror)](https://github.com/pushrocks/smartnetwork)
|
||||
* [docs (typedoc)](https://pushrocks.gitlab.io/smartnetwork/)
|
||||
## Install
|
||||
|
||||
## Status for master
|
||||
[](https://gitlab.com/pushrocks/smartnetwork/commits/master)
|
||||
[](https://gitlab.com/pushrocks/smartnetwork/commits/master)
|
||||
[](https://www.npmjs.com/package/@pushrocks/smartnetwork)
|
||||
[](https://snyk.io/test/npm/@pushrocks/smartnetwork)
|
||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
[](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
[](https://prettier.io/)
|
||||
To install `@push.rocks/smartnetwork`, run the following command in your terminal:
|
||||
|
||||
```bash
|
||||
npm install @push.rocks/smartnetwork --save
|
||||
```
|
||||
|
||||
This command will download `@push.rocks/smartnetwork` and add it to your project's `package.json` file.
|
||||
|
||||
## Usage
|
||||
|
||||
```typescript
|
||||
import * as smartnetwork from 'smartnetwork';
|
||||
const testSmartNetwork = new smartnetwork.SmartNetwork();
|
||||
const run = async () => {
|
||||
// measure average speed over a period of 5 seconds
|
||||
// the structure of speedResult is self explanatory using TypeScript (or the linked TypeDoc above)
|
||||
const speedResult = testSmartNetwork.getSpeed(5000);
|
||||
In this section, we will dive deep into the capabilities of the `@push.rocks/smartnetwork` package, exploring its various features through TypeScript examples. The package is designed to simplify network diagnostics tasks, including speed tests, port availability checks, ping operations, and more.
|
||||
|
||||
//
|
||||
const isLocalPortAvailable: boolean = await testSmartNetwork.isLocalPortAvailable(1234);
|
||||
const isRemotePortAvailable: boolean = await testSmartNetwork.isRemotePortAvailable(
|
||||
'google.com:80'
|
||||
);
|
||||
const isRemotePortAvailable: boolean = await testSmartNetwork.isRemotePortAvailable(
|
||||
'google.com',
|
||||
80
|
||||
);
|
||||
};
|
||||
### Basic Setup
|
||||
|
||||
First, import the package into your project:
|
||||
|
||||
```typescript
|
||||
import { SmartNetwork } from '@push.rocks/smartnetwork';
|
||||
```
|
||||
|
||||
For further information read the linked docs at the top of this readme.
|
||||
Then, create an instance of `SmartNetwork`:
|
||||
|
||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
||||
```typescript
|
||||
const myNetwork = new SmartNetwork();
|
||||
```
|
||||
|
||||
[](https://maintainedby.lossless.com)
|
||||
### Performing a Speed Test
|
||||
|
||||
You can measure the network speed using the `getSpeed` method. This feature leverages Cloudflare's speed test capabilities to assess your internet connection's download and upload speeds.
|
||||
|
||||
```typescript
|
||||
const speedTest = async () => {
|
||||
const speedResult = await myNetwork.getSpeed();
|
||||
console.log(`Download speed: ${speedResult.downloadSpeed} Mbps`);
|
||||
console.log(`Upload speed: ${speedResult.uploadSpeed} Mbps`);
|
||||
console.log(`Latency: ${speedResult.averageTime} ms`);
|
||||
};
|
||||
|
||||
speedTest();
|
||||
```
|
||||
|
||||
### Checking Port Availability Locally
|
||||
|
||||
The `isLocalPortUnused` method allows you to check if a specific port on your local machine is available for use.
|
||||
|
||||
```typescript
|
||||
const checkLocalPort = async (port: number) => {
|
||||
const isUnused = await myNetwork.isLocalPortUnused(port);
|
||||
if (isUnused) {
|
||||
console.log(`Port ${port} is available.`);
|
||||
} else {
|
||||
console.log(`Port ${port} is in use.`);
|
||||
}
|
||||
};
|
||||
|
||||
checkLocalPort(8080); // Example port number
|
||||
```
|
||||
|
||||
### Checking Remote Port Availability
|
||||
|
||||
To verify if a certain port is available on a remote server, use `isRemotePortAvailable`. This can help determine if a service is up and reachable.
|
||||
|
||||
```typescript
|
||||
const checkRemotePort = async (hostname: string, port: number) => {
|
||||
const isAvailable = await myNetwork.isRemotePortAvailable(hostname, port);
|
||||
if (isAvailable) {
|
||||
console.log(`Port ${port} on ${hostname} is available.`);
|
||||
} else {
|
||||
console.log(`Port ${port} on ${hostname} is not available.`);
|
||||
}
|
||||
};
|
||||
|
||||
checkRemotePort('example.com', 443); // Checking HTTPS port on example.com
|
||||
```
|
||||
|
||||
### Using Ping
|
||||
|
||||
The `ping` method allows you to send ICMP packets to a host to measure round-trip time and determine if the host is reachable.
|
||||
|
||||
```typescript
|
||||
const pingHost = async (hostname: string) => {
|
||||
const pingResult = await myNetwork.ping(hostname);
|
||||
if (pingResult.alive) {
|
||||
console.log(`${hostname} is reachable. RTT: ${pingResult.time} ms`);
|
||||
} else {
|
||||
console.log(`${hostname} is not reachable.`);
|
||||
}
|
||||
};
|
||||
|
||||
pingHost('google.com');
|
||||
```
|
||||
|
||||
### Getting Network Gateways
|
||||
|
||||
You can also retrieve information about your network gateways, including the default gateway used by your machine.
|
||||
|
||||
```typescript
|
||||
const showGateways = async () => {
|
||||
const gateways = await myNetwork.getGateways();
|
||||
console.log(gateways);
|
||||
|
||||
const defaultGateway = await myNetwork.getDefaultGateway();
|
||||
console.log(`Default Gateway: `, defaultGateway);
|
||||
};
|
||||
|
||||
showGateways();
|
||||
```
|
||||
|
||||
### Discovering Public IP Addresses
|
||||
|
||||
To find out your public IPv4 and IPv6 addresses, the following method can be used:
|
||||
|
||||
```typescript
|
||||
const showPublicIps = async () => {
|
||||
const publicIps = await myNetwork.getPublicIps();
|
||||
console.log(`Public IPv4: ${publicIps.v4}`);
|
||||
console.log(`Public IPv6: ${publicIps.v6}`);
|
||||
};
|
||||
|
||||
showPublicIps();
|
||||
```
|
||||
|
||||
The `@push.rocks/smartnetwork` package provides an easy-to-use, comprehensive suite of tools for network diagnostics and monitoring, encapsulating complex network operations into simple asynchronous methods. By leveraging TypeScript, developers can benefit from type checking, ensuring that they can work with clear structures and expectations.
|
||||
|
||||
These examples offer a glimpse into the module's utility in real-world scenarios, demonstrating its versatility in handling common network tasks. Whether you're developing a network-sensitive application, diagnosing connectivity issues, or simply curious about your network performance, `@push.rocks/smartnetwork` equips you with the tools you need.
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
25
test/test.ping.ts
Normal file
25
test/test.ping.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { tap, expect, expectAsync } from '@pushrocks/tapbundle';
|
||||
|
||||
import * as smartnetwork from '../ts/index.js';
|
||||
|
||||
let testSmartnetwork: smartnetwork.SmartNetwork;
|
||||
|
||||
tap.test('should create a vlid instance of SmartNetwork', async () => {
|
||||
testSmartnetwork = new smartnetwork.SmartNetwork();
|
||||
expect(testSmartnetwork).toBeInstanceOf(smartnetwork.SmartNetwork);
|
||||
});
|
||||
|
||||
tap.test('should send a ping to Google', async () => {
|
||||
console.log(await testSmartnetwork.ping('google.com'));
|
||||
await expectAsync(testSmartnetwork.ping('google.com')).property('alive').toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('should state when a ping is not alive ', async () => {
|
||||
await expectAsync(testSmartnetwork.ping('notthere.lossless.com')).property('alive').toBeFalse();
|
||||
});
|
||||
|
||||
tap.test('should send a ping to an IP', async () => {
|
||||
await expectAsync(testSmartnetwork.ping('192.168.186.999')).property('alive').toBeFalse();
|
||||
})
|
||||
|
||||
tap.start();
|
32
test/test.ts
32
test/test.ts
@ -1,32 +1,42 @@
|
||||
import { expect, tap } from '@pushrocks/tapbundle';
|
||||
import * as smartnetwork from '../ts/index';
|
||||
import { expect, expectAsync, tap } from '@pushrocks/tapbundle';
|
||||
import * as smartnetwork from '../ts/index.js';
|
||||
|
||||
let testSmartNetwork: smartnetwork.SmartNetwork;
|
||||
|
||||
tap.test('should create a valid instance of SmartNetwork', async () => {
|
||||
testSmartNetwork = new smartnetwork.SmartNetwork();
|
||||
expect(testSmartNetwork).to.be.instanceOf(smartnetwork.SmartNetwork);
|
||||
expect(testSmartNetwork).toBeInstanceOf(smartnetwork.SmartNetwork);
|
||||
});
|
||||
|
||||
tap.test('should perform a speedtest', async () => {
|
||||
let result = await testSmartNetwork.getSpeed();
|
||||
console.log(`Download speed for this instance is ${result.speeds.download}`);
|
||||
console.log(`Upload speed for this instance is ${result.speeds.upload}`);
|
||||
const result = await testSmartNetwork.getSpeed();
|
||||
console.log(`Download speed for this instance is ${result.downloadSpeed}`);
|
||||
console.log(`Upload speed for this instance is ${result.uploadSpeed}`);
|
||||
});
|
||||
|
||||
tap.test('should determine wether a port is free', async () => {
|
||||
await expect(testSmartNetwork.isLocalPortAvailable(8080)).to.eventually.be.true;
|
||||
await expectAsync(testSmartNetwork.isLocalPortUnused(8080)).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('should scan a port', async () => {
|
||||
await expect(testSmartNetwork.isRemotePortAvailable('lossless.com:443')).to.eventually.be.true;
|
||||
await expect(testSmartNetwork.isRemotePortAvailable('lossless.com', 443)).to.be.eventually.true;
|
||||
// await expect(testSmartNetwork.isRemotePortAvailable('lossless.com:444')).to.eventually.be.false;
|
||||
await expectAsync(testSmartNetwork.isRemotePortAvailable('lossless.com:443')).toBeTrue();
|
||||
await expectAsync(testSmartNetwork.isRemotePortAvailable('lossless.com', 443)).toBeTrue();
|
||||
await expectAsync(testSmartNetwork.isRemotePortAvailable('lossless.com:444')).toBeFalse();
|
||||
});
|
||||
|
||||
tap.test('should get the default gateways', async () => {
|
||||
tap.test('should get gateways', async () => {
|
||||
const gatewayResult = await testSmartNetwork.getGateways();
|
||||
console.log(gatewayResult);
|
||||
});
|
||||
|
||||
tap.test('should get the default gateway', async () => {
|
||||
const gatewayResult = await testSmartNetwork.getDefaultGateway();
|
||||
console.log(gatewayResult);
|
||||
});
|
||||
|
||||
tap.test('should get public ips', async () => {
|
||||
const ips = await testSmartNetwork.getPublicIps();
|
||||
console.log(ips);
|
||||
});
|
||||
|
||||
tap.start();
|
||||
|
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@pushrocks/smartnetwork',
|
||||
version: '3.0.2',
|
||||
description: 'network diagnostics'
|
||||
}
|
43
ts/helpers/stats.ts
Normal file
43
ts/helpers/stats.ts
Normal file
@ -0,0 +1,43 @@
|
||||
export function average(values: number[]) {
|
||||
let total = 0;
|
||||
|
||||
for (let i = 0; i < values.length; i += 1) {
|
||||
total += values[i];
|
||||
}
|
||||
|
||||
return total / values.length;
|
||||
}
|
||||
|
||||
export function median(values: number[]) {
|
||||
const half = Math.floor(values.length / 2);
|
||||
|
||||
values.sort((a, b) => a - b);
|
||||
|
||||
if (values.length % 2) return values[half];
|
||||
|
||||
return (values[half - 1] + values[half]) / 2;
|
||||
}
|
||||
|
||||
export function quartile(values: number[], percentile: number) {
|
||||
values.sort((a, b) => a - b);
|
||||
const pos = (values.length - 1) * percentile;
|
||||
const base = Math.floor(pos);
|
||||
const rest = pos - base;
|
||||
|
||||
if (values[base + 1] !== undefined) {
|
||||
return values[base] + rest * (values[base + 1] - values[base]);
|
||||
}
|
||||
|
||||
return values[base];
|
||||
}
|
||||
|
||||
export function jitter(values: number[]) {
|
||||
// Average distance between consecutive latency measurements...
|
||||
let jitters = [];
|
||||
|
||||
for (let i = 0; i < values.length - 1; i += 1) {
|
||||
jitters.push(Math.abs(values[i] - values[i + 1]));
|
||||
}
|
||||
|
||||
return average(jitters);
|
||||
}
|
@ -1 +1 @@
|
||||
export * from './smartnetwork.classes.smartnetwork';
|
||||
export * from './smartnetwork.classes.smartnetwork.js';
|
||||
|
258
ts/smartnetwork.classes.cloudflarespeed.ts
Normal file
258
ts/smartnetwork.classes.cloudflarespeed.ts
Normal file
@ -0,0 +1,258 @@
|
||||
import * as plugins from './smartnetwork.plugins.js';
|
||||
import * as stats from './helpers/stats.js';
|
||||
|
||||
export class CloudflareSpeed {
|
||||
constructor() {}
|
||||
|
||||
public async speedTest() {
|
||||
const latency = await this.measureLatency();
|
||||
|
||||
const serverLocations = await this.fetchServerLocations();
|
||||
const cgiData = await this.fetchCfCdnCgiTrace();
|
||||
|
||||
// lets test the download speed
|
||||
const testDown1 = await this.measureDownload(101000, 10);
|
||||
const testDown2 = await this.measureDownload(1001000, 8);
|
||||
const testDown3 = await this.measureDownload(10001000, 6);
|
||||
const testDown4 = await this.measureDownload(25001000, 4);
|
||||
const testDown5 = await this.measureDownload(100001000, 1);
|
||||
const downloadTests = [...testDown1, ...testDown2, ...testDown3, ...testDown4, ...testDown5];
|
||||
const speedDownload = stats.quartile(downloadTests, 0.9).toFixed(2);
|
||||
|
||||
// lets test the upload speed
|
||||
const testUp1 = await this.measureUpload(11000, 10);
|
||||
const testUp2 = await this.measureUpload(101000, 10);
|
||||
const testUp3 = await this.measureUpload(1001000, 8);
|
||||
const uploadTests = [...testUp1, ...testUp2, ...testUp3];
|
||||
const speedUpload = stats.quartile(uploadTests, 0.9).toFixed(2);
|
||||
|
||||
return {
|
||||
...latency,
|
||||
ip: cgiData.ip,
|
||||
serverLocation: {
|
||||
shortId: cgiData.colo,
|
||||
name: serverLocations[cgiData.colo],
|
||||
availableLocations: serverLocations,
|
||||
},
|
||||
downloadSpeed: speedDownload,
|
||||
uploadSpeed: speedUpload,
|
||||
};
|
||||
}
|
||||
|
||||
public async measureLatency() {
|
||||
const measurements: number[] = [];
|
||||
|
||||
for (let i = 0; i < 20; i += 1) {
|
||||
await this.download(1000).then(
|
||||
(response) => {
|
||||
// TTFB - Server processing time
|
||||
measurements.push(response[4] - response[0] - response[6]);
|
||||
},
|
||||
(error) => {
|
||||
console.log(`Error: ${error}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
maxTime: Math.max(...measurements),
|
||||
minTime: Math.min(...measurements),
|
||||
averageTime: stats.average(measurements),
|
||||
medianTime: stats.median(measurements),
|
||||
jitter: stats.jitter(measurements),
|
||||
};
|
||||
}
|
||||
|
||||
public async measureDownload(bytes: number, iterations: number) {
|
||||
const measurements: number[] = [];
|
||||
|
||||
for (let i = 0; i < iterations; i += 1) {
|
||||
await this.download(bytes).then(
|
||||
async (response) => {
|
||||
const transferTime = response[5] - response[4];
|
||||
measurements.push(await this.measureSpeed(bytes, transferTime));
|
||||
},
|
||||
(error) => {
|
||||
console.log(`Error: ${error}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return measurements;
|
||||
}
|
||||
|
||||
public async measureUpload(bytes: number, iterations: number) {
|
||||
const measurements: number[] = [];
|
||||
|
||||
for (let i = 0; i < iterations; i += 1) {
|
||||
await this.upload(bytes).then(
|
||||
async (response) => {
|
||||
const transferTime = response[6];
|
||||
measurements.push(await this.measureSpeed(bytes, transferTime));
|
||||
},
|
||||
(error) => {
|
||||
console.log(`Error: ${error}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return measurements;
|
||||
}
|
||||
|
||||
public async measureSpeed(bytes: number, duration: number) {
|
||||
return (bytes * 8) / (duration / 1000) / 1e6;
|
||||
}
|
||||
|
||||
public async fetchServerLocations(): Promise<{ [key: string]: string }> {
|
||||
const res = JSON.parse(await this.get('speed.cloudflare.com', '/locations'));
|
||||
|
||||
return res.reduce((data: any, optionsArg: { iata: string; city: string }) => {
|
||||
// Bypass prettier "no-assign-param" rules
|
||||
const data1 = data;
|
||||
|
||||
data1[optionsArg.iata] = optionsArg.city;
|
||||
return data1;
|
||||
}, {});
|
||||
}
|
||||
|
||||
public async get(hostname: string, path: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = plugins.https.request(
|
||||
{
|
||||
hostname,
|
||||
path,
|
||||
method: 'GET',
|
||||
},
|
||||
(res) => {
|
||||
const body: Array<Buffer> = [];
|
||||
res.on('data', (chunk) => {
|
||||
body.push(chunk);
|
||||
});
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve(Buffer.concat(body).toString());
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
req.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
public async download(bytes: number) {
|
||||
const options = {
|
||||
hostname: 'speed.cloudflare.com',
|
||||
path: `/__down?bytes=${bytes}`,
|
||||
method: 'GET',
|
||||
};
|
||||
|
||||
return this.request(options);
|
||||
}
|
||||
|
||||
public async upload(bytes: number) {
|
||||
const data = '0'.repeat(bytes);
|
||||
const options = {
|
||||
hostname: 'speed.cloudflare.com',
|
||||
path: '/__up',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Length': Buffer.byteLength(data),
|
||||
},
|
||||
};
|
||||
|
||||
return this.request(options, data);
|
||||
}
|
||||
|
||||
public async request(options: plugins.https.RequestOptions, data = ''): Promise<number[]> {
|
||||
let started: number;
|
||||
let dnsLookup: number;
|
||||
let tcpHandshake: number;
|
||||
let sslHandshake: number;
|
||||
let ttfb: number;
|
||||
let ended: number;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
started = plugins.perfHooks.performance.now();
|
||||
const req = plugins.https.request(options, (res) => {
|
||||
res.once('readable', () => {
|
||||
ttfb = plugins.perfHooks.performance.now();
|
||||
});
|
||||
res.on('data', () => {});
|
||||
res.on('end', () => {
|
||||
ended = plugins.perfHooks.performance.now();
|
||||
resolve([
|
||||
started,
|
||||
dnsLookup,
|
||||
tcpHandshake,
|
||||
sslHandshake,
|
||||
ttfb,
|
||||
ended,
|
||||
parseFloat(res.headers['server-timing'].slice(22) as any),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
req.on('socket', (socket) => {
|
||||
socket.on('lookup', () => {
|
||||
dnsLookup = plugins.perfHooks.performance.now();
|
||||
});
|
||||
socket.on('connect', () => {
|
||||
tcpHandshake = plugins.perfHooks.performance.now();
|
||||
});
|
||||
socket.on('secureConnect', () => {
|
||||
sslHandshake = plugins.perfHooks.performance.now();
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.write(data);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
public async fetchCfCdnCgiTrace(): Promise<{
|
||||
fl: string;
|
||||
h: string;
|
||||
ip: string;
|
||||
ts: string;
|
||||
visit_scheme: string;
|
||||
uag: string;
|
||||
colo: string;
|
||||
http: string;
|
||||
loc: string;
|
||||
tls: string;
|
||||
sni: string;
|
||||
warp: string;
|
||||
gateway: string;
|
||||
}> {
|
||||
const parseCfCdnCgiTrace = (text: string) =>
|
||||
text
|
||||
.split('\n')
|
||||
.map((i) => {
|
||||
const j = i.split('=');
|
||||
|
||||
return [j[0], j[1]];
|
||||
})
|
||||
.reduce((data: any, [k, v]) => {
|
||||
if (v === undefined) return data;
|
||||
|
||||
// Bypass prettier "no-assign-param" rules
|
||||
const data1 = data;
|
||||
// Object.fromEntries is only supported by Node.js 12 or newer
|
||||
data1[k] = v;
|
||||
|
||||
return data1;
|
||||
}, {});
|
||||
|
||||
return this.get('speed.cloudflare.com', '/cdn-cgi/trace').then(parseCfCdnCgiTrace);
|
||||
}
|
||||
}
|
@ -1,36 +1,6 @@
|
||||
import * as plugins from './smartnetwork.plugins';
|
||||
import * as plugins from './smartnetwork.plugins.js';
|
||||
|
||||
export interface ISpeedtestData {
|
||||
speeds: {
|
||||
download: number;
|
||||
upload: number;
|
||||
originalDownload: number;
|
||||
originalUpload: number;
|
||||
};
|
||||
client: {
|
||||
ip: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
isp: string;
|
||||
isprating: string;
|
||||
rating: number;
|
||||
ispdlavg: number;
|
||||
ispulavg: number;
|
||||
};
|
||||
server: {
|
||||
host: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
location: string;
|
||||
country: string;
|
||||
cc: string;
|
||||
sponsor: string;
|
||||
distance: number;
|
||||
distanceMi: number;
|
||||
ping: number;
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
import { CloudflareSpeed } from './smartnetwork.classes.cloudflarespeed.js';
|
||||
|
||||
/**
|
||||
* SmartNetwork simplifies actions within the network
|
||||
@ -40,16 +10,16 @@ export class SmartNetwork {
|
||||
* get network speed
|
||||
* @param measurementTime
|
||||
*/
|
||||
public async getSpeed(measurementTime = 5000): Promise<ISpeedtestData> {
|
||||
const done = plugins.smartpromise.defer<ISpeedtestData>();
|
||||
const test = plugins.speedtestNet({ maxTime: measurementTime });
|
||||
test.on('data', data => {
|
||||
done.resolve(data);
|
||||
});
|
||||
test.on('error', err => {
|
||||
done.reject(err);
|
||||
});
|
||||
return await done.promise;
|
||||
public async getSpeed() {
|
||||
const cloudflareSpeedInstance = new CloudflareSpeed();
|
||||
const test = await cloudflareSpeedInstance.speedTest();
|
||||
return test;
|
||||
}
|
||||
|
||||
public async ping(hostArg: string, timeoutArg: number = 500): Promise<ReturnType<typeof plugins.smartping.Smartping.prototype.ping>> {
|
||||
const smartpingInstance = new plugins.smartping.Smartping();
|
||||
const pingResult = await smartpingInstance.ping(hostArg, timeoutArg);
|
||||
return pingResult;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,7 +27,7 @@ export class SmartNetwork {
|
||||
* note: false also resolves with false as argument
|
||||
* @param port
|
||||
*/
|
||||
public async isLocalPortAvailable(port: number): Promise<boolean> {
|
||||
public async isLocalPortUnused(port: number): Promise<boolean> {
|
||||
const doneIpV4 = plugins.smartpromise.defer<boolean>();
|
||||
const doneIpV6 = plugins.smartpromise.defer<boolean>();
|
||||
const net = await import('net'); // creates only one instance of net ;) even on multiple calls
|
||||
@ -83,7 +53,7 @@ export class SmartNetwork {
|
||||
|
||||
// test IPv6 space
|
||||
const ipv6Test = net.createServer();
|
||||
ipv6Test.once('error', function(err: any) {
|
||||
ipv6Test.once('error', function (err: any) {
|
||||
if (err.code !== 'EADDRINUSE') {
|
||||
doneIpV6.resolve(false);
|
||||
return;
|
||||
@ -114,12 +84,9 @@ export class SmartNetwork {
|
||||
const domainPart = domainArg.split(':')[0];
|
||||
const port = portArg ? portArg : parseInt(domainArg.split(':')[1], 10);
|
||||
|
||||
plugins.portscanner.checkPortStatus(port, domainPart, (err, status) => {
|
||||
if (err) {
|
||||
// console.log(err);
|
||||
return done.resolve(false);
|
||||
}
|
||||
if (status === 'open') {
|
||||
plugins.isopen(domainPart, port, (response: any) => {
|
||||
console.log(response);
|
||||
if (response[port.toString()].isOpen) {
|
||||
done.resolve(true);
|
||||
} else {
|
||||
done.resolve(false);
|
||||
@ -133,4 +100,38 @@ export class SmartNetwork {
|
||||
const result = plugins.os.networkInterfaces();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async getDefaultGateway(): Promise<{
|
||||
ipv4: plugins.os.NetworkInterfaceInfo;
|
||||
ipv6: plugins.os.NetworkInterfaceInfo;
|
||||
}> {
|
||||
const defaultGatewayName = await plugins.systeminformation.networkInterfaceDefault();
|
||||
if (!defaultGatewayName) {
|
||||
console.log('Cannot determine default gateway');
|
||||
return null;
|
||||
}
|
||||
const gateways = await this.getGateways();
|
||||
const defaultGateway = gateways[defaultGatewayName];
|
||||
return {
|
||||
ipv4: defaultGateway[0],
|
||||
ipv6: defaultGateway[1],
|
||||
};
|
||||
}
|
||||
|
||||
public async getPublicIps() {
|
||||
return {
|
||||
v4: await plugins.publicIp.publicIpv4({
|
||||
timeout: 1000,
|
||||
onlyHttps: true,
|
||||
}).catch(async (err) => {
|
||||
return null
|
||||
}),
|
||||
v6: await plugins.publicIp.publicIpv6({
|
||||
timeout: 1000,
|
||||
onlyHttps: true,
|
||||
}).catch(async (err) => {
|
||||
return null
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,22 @@
|
||||
// native scope
|
||||
import * as os from 'os';
|
||||
import * as https from 'https';
|
||||
import * as perfHooks from 'perf_hooks';
|
||||
|
||||
export {
|
||||
os
|
||||
};
|
||||
export { os, https, perfHooks };
|
||||
|
||||
// @pushrocks scope
|
||||
import * as smartping from '@pushrocks/smartping';
|
||||
import * as smartpromise from '@pushrocks/smartpromise';
|
||||
import * as smartstring from '@pushrocks/smartstring';
|
||||
|
||||
export { smartpromise, smartstring };
|
||||
export { smartpromise, smartping, smartstring };
|
||||
|
||||
// @third party scope
|
||||
const speedtestNet = require('speedtest-net');
|
||||
import * as portscanner from 'portscanner';
|
||||
// @third party scope
|
||||
// @ts-ignore
|
||||
import isopen from 'isopen';
|
||||
// @ts-ignore
|
||||
import * as publicIp from 'public-ip';
|
||||
import * as systeminformation from 'systeminformation';
|
||||
|
||||
export { speedtestNet, portscanner };
|
||||
export { isopen, publicIp, systeminformation };
|
||||
|
5
ts/tsconfig.json
Normal file
5
ts/tsconfig.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true
|
||||
}
|
||||
}
|
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
]
|
||||
}
|
17
tslint.json
17
tslint.json
@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||
"rules": {
|
||||
"semicolon": [true, "always"],
|
||||
"no-console": false,
|
||||
"ordered-imports": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"member-ordering": {
|
||||
"options":{
|
||||
"order": [
|
||||
"static-method"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultSeverity": "warning"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user