Compare commits

...

86 Commits

Author SHA1 Message Date
e89e317bbc 1.1.54 2022-02-15 18:57:42 +01:00
d182832e47 fix(core): update 2022-02-15 18:57:42 +01:00
92059a50de 1.1.53 2022-02-15 18:53:02 +01:00
db80f2df7e fix(core): update 2022-02-15 18:53:02 +01:00
145505b891 1.1.52 2021-05-16 23:39:26 +00:00
f4f50c6a94 fix(core): update 2021-05-16 23:39:25 +00:00
d204059313 1.1.51 2020-09-29 15:22:25 +00:00
00210566d5 fix(core): update 2020-09-29 15:22:25 +00:00
14245b2521 1.1.50 2020-09-29 15:20:41 +00:00
f0fa91e2db fix(core): update 2020-09-29 15:20:40 +00:00
19a1fe1524 1.1.49 2020-08-24 12:04:11 +00:00
27770a8ad1 fix(core): update 2020-08-24 12:04:10 +00:00
ab48f11e83 1.1.48 2020-08-24 12:01:39 +00:00
a0a9e3f824 fix(core): update 2020-08-24 12:01:38 +00:00
c829b06169 1.1.47 2020-01-13 08:00:40 +00:00
80fa40baf4 fix(core): update 2020-01-13 08:00:39 +00:00
3659b80e1e 1.1.46 2020-01-13 07:58:54 +00:00
770e7d46ea fix(core): update 2020-01-13 07:58:54 +00:00
2a46f2a306 1.1.45 2020-01-12 19:36:58 +00:00
eae4d09664 fix(core): update 2020-01-12 19:36:58 +00:00
23a2f597fc 1.1.44 2020-01-12 19:32:20 +00:00
c278249c32 fix(core): update 2020-01-12 19:32:20 +00:00
a32c372374 1.1.43 2019-11-21 17:32:31 +00:00
f98972d9fe fix(core): update 2019-11-21 17:32:30 +00:00
acebe6a381 1.1.42 2019-10-28 16:18:15 +01:00
7031504852 1.1.41 2019-10-27 14:41:49 +01:00
3010a1da9a fix(core): update 2019-10-27 14:41:48 +01:00
cdead33be4 1.1.40 2019-10-27 14:39:07 +01:00
5e23649702 fix(core): update 2019-10-27 14:39:06 +01:00
cc6bd5726a 1.1.39 2019-10-27 14:38:13 +01:00
f487584e80 fix(core): update 2019-10-27 14:38:12 +01:00
443bccd4c9 1.1.38 2019-10-27 14:36:18 +01:00
f359856b1d fix(core): update 2019-10-27 14:36:17 +01:00
bda04f124b 1.1.37 2019-10-27 14:32:27 +01:00
466187fd52 fix(core): update 2019-10-27 14:32:27 +01:00
d22504317e 1.1.36 2019-09-29 16:42:56 +02:00
6e31d84798 fix(core): update 2019-09-29 16:42:56 +02:00
36472b7306 1.1.35 2019-09-29 00:56:56 +02:00
e86f14b8d8 fix(core): update 2019-09-29 00:56:56 +02:00
2b9e7f6dd2 1.1.34 2019-09-29 00:43:37 +02:00
5e4afccf9c fix(core): update 2019-09-29 00:43:37 +02:00
3de7a1a210 1.1.33 2019-09-29 00:42:51 +02:00
bd2a5eedff fix(core): update 2019-09-29 00:42:51 +02:00
aa18357d75 1.1.32 2019-09-28 22:50:35 +02:00
9960aff219 fix(core): update 2019-09-28 22:50:35 +02:00
03d884ed59 1.1.31 2019-09-28 22:27:10 +02:00
9a0ac6fc62 fix(core): update 2019-09-28 22:27:09 +02:00
ad35ea4eb8 1.1.30 2019-09-28 21:40:05 +02:00
ffb0195f04 fix(core): update 2019-09-28 21:40:04 +02:00
78737c24df 1.1.29 2019-09-28 21:34:30 +02:00
6e276eda00 1.1.28 2019-09-28 21:33:14 +02:00
021d26a23a fix(core): update 2019-09-28 21:33:13 +02:00
c9c8a1234c 1.1.27 2019-09-08 18:00:49 +02:00
dffabd905f fix(core): update 2019-09-08 18:00:48 +02:00
36f2707141 1.1.26 2019-09-08 17:57:28 +02:00
b00d674b6f fix(core): update 2019-09-08 17:57:28 +02:00
b09598d465 1.1.25 2019-09-08 17:49:33 +02:00
acc7b2d46f fix(core): update 2019-09-08 17:49:32 +02:00
16a97a420c 1.1.24 2019-09-08 17:47:31 +02:00
a73c78e54b fix(core): update 2019-09-08 17:47:30 +02:00
1f408b5123 1.1.23 2019-08-22 12:40:19 +02:00
284f4967f4 fix(core): update 2019-08-22 12:40:19 +02:00
55c80c1403 1.1.22 2019-08-22 12:38:55 +02:00
7a3e565dbb fix(core): update 2019-08-22 12:38:55 +02:00
6f5d10ccd3 1.1.21 2019-08-22 12:38:12 +02:00
f1ddab72f6 fix(core): update 2019-08-22 12:38:11 +02:00
376225888c 1.1.20 2019-08-21 12:55:20 +02:00
63e8660f6c fix(core): update 2019-08-21 12:55:19 +02:00
2358b1d48f 1.1.19 2019-08-16 22:00:01 +02:00
9db29bacc2 fix(core): update 2019-08-16 22:00:01 +02:00
5f27b6834c 1.1.18 2019-08-16 21:43:10 +02:00
6717ecf80c fix(core): update 2019-08-16 21:43:09 +02:00
7784f99878 1.1.17 2019-08-16 21:38:50 +02:00
54a0521f9e fix(core): update 2019-08-16 21:38:50 +02:00
ef25315d59 1.1.16 2019-06-12 15:16:28 +02:00
74b6bf230f fix(core): update 2019-06-12 15:16:27 +02:00
fe693e6383 1.1.15 2019-04-23 00:14:31 +02:00
6014e94ee0 fix(core): update 2019-04-23 00:14:30 +02:00
88927fa6f8 1.1.14 2018-08-14 01:47:55 +02:00
e8133247f7 fix(ci): remove ci dependencies 2018-08-14 01:47:54 +02:00
4e51ed315e 1.1.13 2018-08-14 01:46:13 +02:00
0ffc44b3ef fix(request): now allows sending of strings 2018-08-14 01:46:12 +02:00
a8291febec 1.1.12 2018-07-20 01:06:25 +02:00
c0704eb2d8 fix(core): update 2018-07-20 01:06:25 +02:00
9eeb9c16b6 1.1.11 2018-07-20 00:50:36 +02:00
52bf520eb9 fix(small fix): update 2018-07-20 00:50:36 +02:00
17 changed files with 27359 additions and 723 deletions

20
.gitignore vendored
View File

@ -1,4 +1,20 @@
node_modules/
.nogit/
# artifacts
coverage/
public/
pages/
pages/
# installs
node_modules/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_*/
# custom

View File

@ -1,16 +1,19 @@
# gitzone standard
image: hosttoday/ht-docker-node:npmci
# gitzone ci_default
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,109 +21,115 @@ 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 command npm install -g snyk
- npmci command npm install --ignore-scripts
- npmci command snyk test
- npmci npm prepare
- 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
# ====================
testLEGACY:
stage: test
script:
- npmci node install legacy
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
allow_failure: true
testLTS:
testStable:
stage: test
script:
- npmci node install lts
- 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
- notpriv
testSTABLE:
- docker
testBuild:
stage: test
script:
- npmci node install stable
- npmci npm install
- npmci npm test
- 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 stable
- npmci npm publish
- npmci node install stable
- npmci npm publish
only:
- tags
- tags
tags:
- docker
- notpriv
- lossless
- docker
- notpriv
# ====================
# metadata stage
# ====================
codequality:
stage: metadata
image: docker:stable
allow_failure: true
services:
- docker:stable-dind
only:
- tags
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--env SOURCE_CODE="$PWD"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
artifacts:
paths: [codeclimate.json]
- 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-node:npmci
stage: metadata
script:
- npmci command npm install -g typedoc typescript
- npmci node install lts
- npmci command npm install -g @gitzone/tsdoc
- npmci npm prepare
- npmci npm install
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/
- npmci command tsdoc
tags:
- lossless
- docker
- notpriv
only:
@ -128,15 +137,5 @@ pages:
artifacts:
expire_in: 1 week
paths:
- public
allow_failure: true
windowsCompatibility:
image: stefanscherer/node-windows:10-build-tools
stage: metadata
script:
- npm install & npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- windows
- public
allow_failure: true

11
.vscode/launch.json vendored Normal file
View 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
View 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"]
}
}
}
}
}
}
]
}

View File

@ -1,69 +0,0 @@
# smartrequest
dropin replacement for request
## Availabililty
[![npm](https://push.rocks/assets/repo-button-npm.svg)](https://www.npmjs.com/package/smartrequest)
[![git](https://push.rocks/assets/repo-button-git.svg)](https://GitLab.com/pushrocks/smartrequest)
[![git](https://push.rocks/assets/repo-button-mirror.svg)](https://github.com/pushrocks/smartrequest)
[![docs](https://push.rocks/assets/repo-button-docs.svg)](https://pushrocks.gitlab.io/smartrequest/)
## Status for master
[![build status](https://GitLab.com/pushrocks/smartrequest/badges/master/build.svg)](https://GitLab.com/pushrocks/smartrequest/commits/master)
[![coverage report](https://GitLab.com/pushrocks/smartrequest/badges/master/coverage.svg)](https://GitLab.com/pushrocks/smartrequest/commits/master)
[![npm downloads per month](https://img.shields.io/npm/dm/smartrequest.svg)](https://www.npmjs.com/package/smartrequest)
[![Dependency Status](https://david-dm.org/pushrocks/smartrequest.svg)](https://david-dm.org/pushrocks/smartrequest)
[![bitHound Dependencies](https://www.bithound.io/github/pushrocks/smartrequest/badges/dependencies.svg)](https://www.bithound.io/github/pushrocks/smartrequest/master/dependencies/npm)
[![bitHound Code](https://www.bithound.io/github/pushrocks/smartrequest/badges/code.svg)](https://www.bithound.io/github/pushrocks/smartrequest)
[![TypeScript](https://img.shields.io/badge/TypeScript-2.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![node](https://img.shields.io/badge/node->=%206.x.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
## Usage
Use TypeScript for best in class instellisense.
> note: smartrequest uses the **native** node request module under the hood (not the one from npm)
```javascript
import * as smartrequest from 'smartrequest'
// simple post
let options: smartrequest.ISmartRequestOptions = { // typed options
headers: {
"Content-Type": "application/json"
"Authorization": "Bearer token"
},
requestBody: {
key1: 'value1',
key2: 3
}
}
smartrequest.post('https://example.com', options).then(res => {
console.log(res.status)
console.log(res.body) // if json, body will be parsed automatically
}).catch(err => {
console.log(err)
})
// also available
smartrequest.get(...)
smartrequest.put(...)
smartrequest.del(...)
// streaming
smartrequest.get('https://example.com/bigfile.mp4', optionsArg, true).then(res => { // third arg = true signals streaming
console.log(res.status)
res.on('data', data => {
// do something with the data chunk here
}
res.on('end', () => {
// do something when things have ended
})
})
```
[![npm](https://push.rocks/assets/repo-header.svg)](https://push.rocks)

View File

@ -3,9 +3,18 @@
"coverageTreshold": 50
},
"npmci": {
"npmGlobalTools": [
"npmts"
],
"npmGlobalTools": [],
"npmAccessLevel": "public"
},
"gitzone": {
"projectType": "npm",
"module": {
"githost": "gitlab.com",
"gitscope": "pushrocks",
"gitrepo": "smartrequest",
"description": "dropin replacement for request",
"npmPackagename": "@pushrocks/smartrequest",
"license": "MIT"
}
}
}

27304
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
{
"name": "@pushrocks/smartrequest",
"version": "1.1.10",
"version": "1.1.54",
"private": false,
"description": "dropin replacement for request",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"scripts": {
"test": "tsrun test/test.ts",
"build": "(npmts)"
"test": "(tstest test/ --web)",
"build": "(tsbuild --web)"
},
"repository": {
"type": "git",
@ -23,13 +23,33 @@
},
"homepage": "https://gitlab.com/pushrocks/smartrequest#README",
"dependencies": {
"@pushrocks/smartpromise": "^2.0.5",
"@types/form-data": "^2.2.1",
"form-data": "^2.3.2"
"@pushrocks/smartpromise": "^3.1.6",
"@pushrocks/smarturl": "^2.0.1",
"agentkeepalive": "^4.2.0",
"form-data": "^4.0.0"
},
"devDependencies": {
"@gitzone/tsrun": "^1.1.9",
"@pushrocks/tapbundle": "^3.0.1",
"@types/node": "^10.5.2"
}
"@gitzone/tsbuild": "^2.1.29",
"@gitzone/tsrun": "^1.2.18",
"@gitzone/tstest": "^1.0.64",
"@pushrocks/tapbundle": "^4.0.7",
"@types/node": "^17.0.18",
"tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0"
},
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"browserslist": [
"last 1 chrome versions"
]
}

96
readme.md Normal file
View File

@ -0,0 +1,96 @@
# @pushrocks/smartrequest
dropin replacement for request
## Availabililty and Links
* [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartrequest)
* [gitlab.com (source)](https://gitlab.com/pushrocks/smartrequest)
* [github.com (source mirror)](https://github.com/pushrocks/smartrequest)
* [docs (typedoc)](https://pushrocks.gitlab.io/smartrequest/)
## Status for master
Status Category | Status Badge
-- | --
GitLab Pipelines | [![pipeline status](https://gitlab.com/pushrocks/smartrequest/badges/master/pipeline.svg)](https://lossless.cloud)
GitLab Pipline Test Coverage | [![coverage report](https://gitlab.com/pushrocks/smartrequest/badges/master/coverage.svg)](https://lossless.cloud)
npm | [![npm downloads per month](https://badgen.net/npm/dy/@pushrocks/smartrequest)](https://lossless.cloud)
Snyk | [![Known Vulnerabilities](https://badgen.net/snyk/pushrocks/smartrequest)](https://lossless.cloud)
TypeScript Support | [![TypeScript](https://badgen.net/badge/TypeScript/>=%203.x/blue?icon=typescript)](https://lossless.cloud)
node Support | [![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
Code Style | [![Code Style](https://badgen.net/badge/style/prettier/purple)](https://lossless.cloud)
PackagePhobia (total standalone install weight) | [![PackagePhobia](https://badgen.net/packagephobia/install/@pushrocks/smartrequest)](https://lossless.cloud)
PackagePhobia (package size on registry) | [![PackagePhobia](https://badgen.net/packagephobia/publish/@pushrocks/smartrequest)](https://lossless.cloud)
BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bundlephobia/minzip/@pushrocks/smartrequest)](https://lossless.cloud)
Platform support | [![Supports Windows 10](https://badgen.net/badge/supports%20Windows%2010/yes/green?icon=windows)](https://lossless.cloud) [![Supports Mac OS X](https://badgen.net/badge/supports%20Mac%20OS%20X/yes/green?icon=apple)](https://lossless.cloud)
## Usage
Use TypeScript for best in class instellisense.
### Features
- supports http
- supports https
- supports unix socks
- supports formData
- supports file uploads
- supports best practice keepAlive
- dedicated functions for working with JSON request/response cycles
- written in TypeScript
- continuously updated
- uses node native http and https modules
- used in modules like @pushrocks/smartproxy and @apiglobal/typedrequest
- commercial support available at [https://lossless.support](https://lossless.support)
> note: smartrequest uses the **native** node http/https modules under the hood (not the bloated one from npm)
```javascript
import * as smartrequest from 'smartrequest'
// simple post
const options: smartrequest.ISmartRequestOptions = { // typed options
headers: {
"Content-Type": "application/json"
"Authorization": "Bearer token"
},
requestBody: JSON.stringify({
key1: 'value1',
key2: 3
})
}
smartrequest.request('https://example.com', options).then(res => {
console.log(res.status)
console.log(res.body) // if json, body will be parsed automatically
}).catch(err => {
console.log(err)
})
// dedicated JSON methods are available:
smartrequest.getJson(...)
smartrequest.postJson(...)
smartrequest.putJson(...)
smartrequest.delJson(...)
// streaming
smartrequest.get('https://example.com/bigfile.mp4', optionsArg, true).then(res => { // third arg = true signals streaming
console.log(res.status)
res.on('data', data => {
// do something with the data chunk here
}
res.on('end', () => {
// do something when things have ended
})
})
```
## Contribution
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
For further information read the linked docs at the top of this readme.
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
[![repo-footer](https://lossless.gitlab.io/publicrelations/repofooter.svg)](https://maintainedby.lossless.com)

View File

@ -1,39 +1,38 @@
import { tap, expect } from '@pushrocks/tapbundle';
import { tap, expect, expectAsync } from '@pushrocks/tapbundle';
import * as smartrequest from '../ts/index';
tap.test('should request a html document over https', async () => {
await expect(smartrequest.getJson('https://encrypted.google.com/'))
.to.eventually.property('body')
.be.a('string');
await expectAsync(smartrequest.getJson('https://encrypted.google.com/')).toHaveProperty('body');
});
tap.test('should request a JSON document over https', async () => {
await expect(smartrequest.getJson('https://jsonplaceholder.typicode.com/posts/1'))
.to.eventually.property('body')
await expectAsync(smartrequest.getJson('https://jsonplaceholder.typicode.com/posts/1'))
.property('body')
.property('id')
.equal(1);
.toEqual(1);
});
tap.test('should post a JSON document over http', async () => {
await expect(smartrequest.postJson('http://md5.jsontest.com/?text=example_text'))
.to.eventually.property('body')
tap.skip.test('should post a JSON document over http', async () => {
await expectAsync(smartrequest.postJson('http://md5.jsontest.com/?text=example_text'))
.property('body')
.property('md5')
.equal('fa4c6baa0812e5b5c80ed8885e55a8a6');
.toEqual('fa4c6baa0812e5b5c80ed8885e55a8a6');
});
tap.skip.test('should deal with unix socks', async () => {
const socketResponse = await smartrequest.request('http://unix:/var/run/docker.sock:/containers/json', {
headers: {
"Content-Type": "application/json",
"Host": "docker.sock"
const socketResponse = await smartrequest.request(
'http://unix:/var/run/docker.sock:/containers/json',
{
headers: {
'Content-Type': 'application/json',
Host: 'docker.sock',
},
}
});
);
console.log(socketResponse.body);
});
tap.skip.test('should correctly upload a file using formData', async () => {
})
tap.skip.test('should correctly upload a file using formData', async () => {});
tap.start();

View File

@ -8,20 +8,24 @@ export const getBinary = async (
domainArg: string,
optionsArg: interfaces.ISmartRequestOptions = {}
) => {
optionsArg = {
...optionsArg,
autoJsonParse: false,
};
const done = plugins.smartpromise.defer();
const response = await request(domainArg, optionsArg, true);
const data = [];
const data: Array<Buffer> = [];
response
.on('data', function(chunk) {
.on('data', function (chunk: Buffer) {
data.push(chunk);
})
.on('end', function() {
.on('end', function () {
//at this point data is an array of Buffers
//so Buffer.concat() can make us a new Buffer
//of all of them together
const buffer = Buffer.concat(data);
response.body = buffer.toString('binary');
response.body = buffer;
done.resolve();
});
await done.promise;

View File

@ -1,28 +1,45 @@
import * as plugins from "./smartrequest.plugins";
import * as interfaces from "./smartrequest.interfaces";
import { request } from "./smartrequest.request";
import * as plugins from './smartrequest.plugins';
import * as interfaces from './smartrequest.interfaces';
import { request } from './smartrequest.request';
/**
* the interfae for FormFieldData
*/
export interface IFormField {
name: string;
type: "string" | "filePath" | "Buffer";
payload: string;
type: 'string' | 'filePath' | 'Buffer';
payload: string | Buffer;
fileName?: string;
contentType?: string;
}
const appendFormField = async (
formDataArg: plugins.formData,
formDataField: IFormField
) => {
if (formDataField.type === "filePath") {
let fileData = plugins.fs.readFileSync(
plugins.path.join(process.cwd(), formDataField.payload)
);
formDataArg.append("file", fileData, {
filename: 'upload.pdf',
contentType: 'application/pdf'
});
const appendFormField = async (formDataArg: plugins.formData, formDataField: IFormField) => {
switch (formDataField.type) {
case 'string':
formDataArg.append(formDataField.name, formDataField.payload);
break;
case 'filePath':
if (typeof formDataField.payload !== 'string') {
throw new Error(
`Payload for key ${
formDataField.name
} must be of type string. Got ${typeof formDataField.payload} instead.`
);
}
const fileData = plugins.fs.readFileSync(
plugins.path.join(process.cwd(), formDataField.payload)
);
formDataArg.append('file', fileData, {
filename: formDataField.fileName ? formDataField.fileName : 'upload.pdf',
contentType: 'application/pdf',
});
break;
case 'Buffer':
formDataArg.append(formDataField.name, formDataField.payload, {
filename: formDataField.fileName ? formDataField.fileName : 'upload.pdf',
contentType: formDataField.contentType ? formDataField.contentType : 'application/pdf',
});
break;
}
};
@ -35,15 +52,47 @@ export const postFormData = async (
for (const formField of payloadArg) {
await appendFormField(form, formField);
}
const requestOptions = Object.assign({}, optionsArg, {
const requestOptions = {
...optionsArg,
method: 'POST',
headers: {
...(optionsArg.headers),
...form.getHeaders()
...optionsArg.headers,
...form.getHeaders(),
},
requestBody: form
});
requestBody: form,
};
// lets fire the actual request for sending the formdata
const response = await request(urlArg, requestOptions);
return response;
};
export const postFormDataUrlEncoded = async (
urlArg: string,
optionsArg: interfaces.ISmartRequestOptions = {},
payloadArg: { key: string; content: string }[]
) => {
const requestOptions = {
...optionsArg,
method: 'POST',
headers: {
...optionsArg.headers,
'content-type': 'application/x-www-form-urlencoded',
},
};
let resultString = '';
for (const keyContentPair of payloadArg) {
if (resultString) {
resultString += '&';
}
resultString += `${encodeURIComponent(keyContentPair.key)}=${encodeURIComponent(
keyContentPair.content
)}`;
}
// lets fire the actual request for sending the formdata
const response = await request(urlArg + resultString, requestOptions);
return response;
};

View File

@ -2,5 +2,8 @@ import * as plugins from './smartrequest.plugins';
import * as https from 'https';
export interface ISmartRequestOptions extends https.RequestOptions {
keepAlive?: boolean;
requestBody?: any;
autoJsonParse?: boolean;
queryParams?: { [key: string]: string };
}

View File

@ -14,7 +14,7 @@ export const getJson = async (
) => {
optionsArg.method = 'GET';
optionsArg.headers = {
...optionsArg.headers
...optionsArg.headers,
};
let response = await request(domainArg, optionsArg);
return response;
@ -37,7 +37,7 @@ export const postJson = async (
// assign the right Content-Type, leaving all other headers in place
optionsArg.headers = {
...optionsArg.headers,
'Content-Type': 'application/json'
'Content-Type': 'application/json',
};
}
let response = await request(domainArg, optionsArg);

View File

@ -1,10 +1,19 @@
import * as formData from 'form-data';
// node native scope
import * as fs from 'fs';
import * as http from 'http';
import * as https from 'https';
import * as path from 'path';
import * as url from 'url';
export { http, https, fs, path };
// pushrocks scope
import * as smartpromise from '@pushrocks/smartpromise';
import * as smarturl from '@pushrocks/smarturl';
export {formData, http, https, fs, path, url, smartpromise };
export { smartpromise, smarturl };
// third party scope
import agentkeepalive from 'agentkeepalive';
import formData from 'form-data';
export { agentkeepalive, formData };

View File

@ -1,27 +1,31 @@
import * as https from "https";
import * as plugins from "./smartrequest.plugins";
import * as interfaces from "./smartrequest.interfaces";
import * as plugins from './smartrequest.plugins';
import * as interfaces from './smartrequest.interfaces';
import { IncomingMessage } from "http";
import { IncomingMessage } from 'http';
export interface IExtendedIncomingMessage extends IncomingMessage {
body: any;
}
const buildUtf8Response = (
incomingMessageArg: IncomingMessage
incomingMessageArg: IncomingMessage,
autoJsonParse = true
): Promise<IExtendedIncomingMessage> => {
let done = plugins.smartpromise.defer<IExtendedIncomingMessage>();
const done = plugins.smartpromise.defer<IExtendedIncomingMessage>();
// Continuously update stream with data
let body = "";
incomingMessageArg.on("data", function(chunkArg) {
let body = '';
incomingMessageArg.on('data', (chunkArg) => {
body += chunkArg;
});
incomingMessageArg.on("end", function() {
try {
(incomingMessageArg as IExtendedIncomingMessage).body = JSON.parse(body);
} catch (err) {
incomingMessageArg.on('end', () => {
if (autoJsonParse) {
try {
(incomingMessageArg as IExtendedIncomingMessage).body = JSON.parse(body);
} catch (err) {
(incomingMessageArg as IExtendedIncomingMessage).body = body;
}
} else {
(incomingMessageArg as IExtendedIncomingMessage).body = body;
}
done.resolve(incomingMessageArg as IExtendedIncomingMessage);
@ -46,79 +50,135 @@ const parseSocketPathAndRoute = (stringToParseArg: string) => {
const result = parseRegex.exec(stringToParseArg);
return {
socketPath: result[1],
path: result[2]
}
}
path: result[2],
};
};
/**
* a custom http agent to make sure we can set custom keepAlive options for speedy subsequent calls
*/
const httpAgent = new plugins.agentkeepalive();
/**
* a custom http agent to make sure we can set custom keepAlive options for speedy subsequent calls
*/
const httpAgentKeepAliveFalse = new plugins.http.Agent({
maxFreeSockets: 0,
keepAlive: false,
keepAliveMsecs: 0,
});
/**
* a custom https agent to make sure we can set custom keepAlive options for speedy subsequent calls
*/
const httpsAgent = new plugins.agentkeepalive.HttpsAgent();
/**
* a custom https agent to make sure we can set custom keepAlive options for speedy subsequent calls
*/
const httpsAgentKeepAliveFalse = new plugins.https.Agent({
maxFreeSockets: 0,
keepAlive: false,
keepAliveMsecs: 0,
});
export let request = async (
domainArg: string,
urlArg: string,
optionsArg: interfaces.ISmartRequestOptions = {},
streamArg: boolean = false
responseStreamArg: boolean = false,
requestDataFunc: (req: plugins.http.ClientRequest) => void = null
): Promise<IExtendedIncomingMessage> => {
let done = plugins.smartpromise.defer<any>();
const done = plugins.smartpromise.defer<any>();
// merge options
const defaultOptions: interfaces.ISmartRequestOptions = {
// agent: agent,
autoJsonParse: true,
keepAlive: true,
};
optionsArg = {
...defaultOptions,
...optionsArg,
};
// parse url
let parsedUrl: plugins.url.Url;
parsedUrl = plugins.url.parse(domainArg);
const parsedUrl = plugins.smarturl.Smarturl.createFromUrl(urlArg, {
searchParams: optionsArg.queryParams || {},
});
optionsArg.hostname = parsedUrl.hostname;
if (parsedUrl.port) {
optionsArg.port = parseInt(parsedUrl.port);
optionsArg.port = parseInt(parsedUrl.port, 10);
}
optionsArg.path = parsedUrl.path;
optionsArg.queryParams = parsedUrl.searchParams;
// determine if unixsock
if(testForUnixSock(domainArg)) {
const detailedUnixPath = parseSocketPathAndRoute(optionsArg.path)
if (testForUnixSock(urlArg)) {
const detailedUnixPath = parseSocketPathAndRoute(optionsArg.path);
optionsArg.socketPath = detailedUnixPath.socketPath;
optionsArg.path = detailedUnixPath.path;
}
// TODO: support tcp sockets
// lets determine the request module to use
const requestModule = (() => {
if (parsedUrl.protocol === "https:") {
return plugins.https;
} else if (parsedUrl.protocol === "http:") {
return plugins.http;
} else {
throw new Error(`unsupported protocol: ${parsedUrl.protocol}`);
switch (true) {
case parsedUrl.protocol === 'https:' && optionsArg.keepAlive:
optionsArg.agent = httpsAgent;
return plugins.https;
case parsedUrl.protocol === 'https:' && !optionsArg.keepAlive:
optionsArg.agent = httpsAgentKeepAliveFalse;
return plugins.https;
case parsedUrl.protocol === 'http:' && optionsArg.keepAlive:
optionsArg.agent = httpAgent;
return plugins.http;
case parsedUrl.protocol === 'http:' && !optionsArg.keepAlive:
optionsArg.agent = httpAgentKeepAliveFalse;
return plugins.http;
}
})() as typeof plugins.https;
if (!requestModule) {
console.error(`The request to ${urlArg} is missing a viable protocol. Must be http or https`);
return;
}
// lets perform the actual request
let request = requestModule.request(optionsArg);
const requestToFire = requestModule.request(optionsArg, async (response) => {
if (responseStreamArg) {
done.resolve(response);
} else {
const builtResponse = await buildUtf8Response(response, optionsArg.autoJsonParse);
done.resolve(builtResponse);
}
});
// lets write the requestBody
if (optionsArg.requestBody) {
if (
typeof optionsArg.requestBody !== "string"
&& !(optionsArg.requestBody instanceof plugins.formData)
) {
optionsArg.requestBody = JSON.stringify(optionsArg.requestBody);
request.write(optionsArg.requestBody);
request.end();
} else if (optionsArg.requestBody instanceof plugins.formData) {
optionsArg.requestBody.pipe(request);
if (optionsArg.requestBody instanceof plugins.formData) {
optionsArg.requestBody.pipe(requestToFire).on('finish', (event: any) => {
requestToFire.end();
});
} else {
if (typeof optionsArg.requestBody !== 'string') {
optionsArg.requestBody = JSON.stringify(optionsArg.requestBody);
}
requestToFire.write(optionsArg.requestBody);
requestToFire.end();
}
} else if (requestDataFunc) {
requestDataFunc(requestToFire);
} else {
request.end();
requestToFire.end();
}
// lets handle an error
request.on("error", e => {
requestToFire.on('error', (e) => {
console.error(e);
});
// lets handle the response
request.on("response", async response => {
if (streamArg) {
done.resolve(response);
} else {
const builtResponse = await buildUtf8Response(response)
done.resolve(builtResponse);
}
});
const result = await done.promise;
return result;
};

View File

@ -1,3 +1,17 @@
{
"extends": "tslint-config-standard"
"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"
}