Add typescript definitions and tests
parent
db4af38f2d
commit
3c72e098ae
16
.eslintrc
16
.eslintrc
|
@ -14,5 +14,19 @@
|
|||
"VariableDeclarator": true
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
"standard",
|
||||
"plugin:promise/recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"semi": [2, "always"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import * as rp from 'request-promise/errors';
|
||||
import cloudscraper = require('.');
|
||||
import http = require('http');
|
||||
|
||||
export interface RequestError extends rp.RequestError {
|
||||
options: cloudscraper.Options;
|
||||
errorType: 0;
|
||||
}
|
||||
|
||||
export interface RequestErrorConstructor extends Error {
|
||||
new(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): RequestError;
|
||||
|
||||
(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): RequestError;
|
||||
|
||||
prototype: RequestError;
|
||||
}
|
||||
|
||||
export const RequestError: RequestErrorConstructor;
|
||||
|
||||
export interface CaptchaError extends rp.RequestError {
|
||||
options: cloudscraper.Options;
|
||||
errorType: 1;
|
||||
}
|
||||
|
||||
export interface CaptchaErrorConstructor extends Error {
|
||||
new(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): RequestError;
|
||||
|
||||
(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): RequestError;
|
||||
|
||||
prototype: CaptchaError;
|
||||
}
|
||||
|
||||
export const CaptchaError: CaptchaErrorConstructor;
|
||||
|
||||
export interface CloudflareError extends rp.RequestError {
|
||||
options: cloudscraper.Options;
|
||||
errorType: 2 | 4;
|
||||
}
|
||||
|
||||
export interface CloudflareErrorConstructor extends Error {
|
||||
new(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): RequestError;
|
||||
|
||||
(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): RequestError;
|
||||
|
||||
prototype: CloudflareError;
|
||||
}
|
||||
|
||||
export const CloudflareError: CloudflareErrorConstructor;
|
||||
|
||||
export interface ParserError extends rp.RequestError {
|
||||
options: cloudscraper.Options;
|
||||
errorType: 3;
|
||||
}
|
||||
|
||||
export interface ParserErrorConstructor extends Error {
|
||||
new(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): RequestError;
|
||||
|
||||
(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): RequestError;
|
||||
|
||||
prototype: ParserError;
|
||||
}
|
||||
|
||||
export const ParserError: ParserErrorConstructor;
|
||||
|
||||
export interface StatusCodeError extends rp.RequestError {
|
||||
options: cloudscraper.Options;
|
||||
statusCode: number;
|
||||
errorType: 5;
|
||||
}
|
||||
|
||||
export interface StatusCodeErrorConstructor extends Error {
|
||||
new(statusCode: number, body: any, options: cloudscraper.Options, response: http.IncomingMessage): StatusCodeError;
|
||||
|
||||
(statusCode: number, body: any, options: cloudscraper.Options, response: http.IncomingMessage): StatusCodeError;
|
||||
|
||||
prototype: StatusCodeError;
|
||||
}
|
||||
|
||||
export const StatusCodeError: StatusCodeErrorConstructor;
|
||||
|
||||
export interface TransformError extends rp.RequestError {
|
||||
options: cloudscraper.Options;
|
||||
errorType: 6;
|
||||
}
|
||||
|
||||
export interface TransformErrorConstructor extends Error {
|
||||
new(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): TransformError;
|
||||
|
||||
(cause: any, options: cloudscraper.Options, response: http.IncomingMessage): TransformError;
|
||||
|
||||
prototype: TransformError;
|
||||
}
|
||||
|
||||
export const TransformError: TransformErrorConstructor;
|
|
@ -0,0 +1,89 @@
|
|||
import { Url } from 'url';
|
||||
import http = require('http');
|
||||
import https = require('https');
|
||||
import Promise = require('bluebird');
|
||||
import request = require('request');
|
||||
import rp = require('request-promise');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import errors = require('./errors');
|
||||
|
||||
declare namespace cloudscraper {
|
||||
interface Cloudscraper extends rp.RequestPromise, BaseOptions {
|
||||
cloudflareTimeout?: number;
|
||||
realEncoding: string | null;
|
||||
// Identify this request as a Cloudscraper request
|
||||
cloudscraper: boolean;
|
||||
}
|
||||
|
||||
interface Captcha {
|
||||
submit(error?: Error): void;
|
||||
|
||||
url: string; // <- deprecated
|
||||
siteKey: string;
|
||||
uri: Url;
|
||||
form: {
|
||||
[key: string]: string;
|
||||
// Secret form value
|
||||
s: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Response extends request.Response {
|
||||
isCloudflare?: boolean;
|
||||
isHTML?: boolean;
|
||||
isCaptcha?: boolean;
|
||||
|
||||
// JS Challenge
|
||||
challenge?: string;
|
||||
}
|
||||
|
||||
interface CaptchaResponse extends Response {
|
||||
captcha: Captcha;
|
||||
isCaptcha: true;
|
||||
}
|
||||
|
||||
type Requester =
|
||||
rp.RequestPromiseAPI
|
||||
| request.RequestAPI<request.Request, request.CoreOptions, request.RequiredUriUrl>;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type CaptchaHandler = (options: Options, response: CaptchaResponse, body?: any) => Promise<any> | void;
|
||||
|
||||
interface BaseOptions {
|
||||
// The default export of either request or request-promise
|
||||
requester?: Requester;
|
||||
// Reduce Cloudflare's timeout to cloudflareMaxTimeout if it is excessive
|
||||
cloudflareMaxTimeout?: number;
|
||||
// Support only this max challenges in row. If CF returns more, throw an error
|
||||
challengesToSolve?: number;
|
||||
// Remove Cloudflare's email protection
|
||||
decodeEmails?: boolean;
|
||||
|
||||
onCaptcha?: CaptchaHandler;
|
||||
}
|
||||
|
||||
interface DefaultOptions extends Required<BaseOptions>, rp.RequestPromiseOptions {
|
||||
// Override the parsed timeout
|
||||
cloudflareTimeout?: number;
|
||||
agentOptions?: (http.AgentOptions | https.AgentOptions) & {
|
||||
ciphers?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface CoreOptions extends BaseOptions, rp.RequestPromiseOptions {
|
||||
cloudflareTimeout?: number;
|
||||
realEncoding?: string | null;
|
||||
}
|
||||
|
||||
interface CloudscraperAPI extends request.RequestAPI<Cloudscraper, CoreOptions, request.RequiredUriUrl> {
|
||||
defaultParams: DefaultOptions;
|
||||
}
|
||||
|
||||
type OptionsWithUri = request.UriOptions & CoreOptions;
|
||||
type OptionsWithUrl = request.UrlOptions & CoreOptions;
|
||||
type Options = OptionsWithUri | OptionsWithUrl;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-redeclare
|
||||
declare const cloudscraper: cloudscraper.CloudscraperAPI;
|
||||
export = cloudscraper;
|
|
@ -0,0 +1,86 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { expectType } from 'tsd';
|
||||
import { URL } from 'url';
|
||||
import {
|
||||
Options, Cloudscraper, CaptchaHandler, CoreOptions, DefaultOptions,
|
||||
CaptchaResponse, Captcha
|
||||
} from './index';
|
||||
import Promise = require('bluebird');
|
||||
import request = require('request');
|
||||
import rp = require('request-promise');
|
||||
import cloudscraper = require('./index');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import errors = require('./errors');
|
||||
|
||||
const noop = (): void => {};
|
||||
|
||||
expectType<Options>({ uri: '' });
|
||||
expectType<Options>({ url: '' });
|
||||
|
||||
expectType<Options>({ uri: '', requester: request });
|
||||
expectType<Options>({ uri: '', requester: rp });
|
||||
|
||||
expectType<Cloudscraper>(cloudscraper({ uri: '' }));
|
||||
expectType<Cloudscraper>(cloudscraper.get({ uri: '' }));
|
||||
expectType<Cloudscraper>(cloudscraper.post({ uri: '' }));
|
||||
expectType<Cloudscraper>(cloudscraper.put({ uri: '' }));
|
||||
expectType<Cloudscraper>(cloudscraper.delete({ uri: '' }));
|
||||
expectType<Cloudscraper>(cloudscraper.del({ uri: '' }));
|
||||
expectType<Cloudscraper>(cloudscraper.head({ uri: '' }));
|
||||
expectType<Cloudscraper>(cloudscraper.patch({ uri: '' }));
|
||||
|
||||
expectType<Cloudscraper>(cloudscraper(''));
|
||||
expectType<Cloudscraper>(cloudscraper.get(''));
|
||||
expectType<Cloudscraper>(cloudscraper.post(''));
|
||||
expectType<Cloudscraper>(cloudscraper.put(''));
|
||||
expectType<Cloudscraper>(cloudscraper.delete(''));
|
||||
expectType<Cloudscraper>(cloudscraper.del(''));
|
||||
expectType<Cloudscraper>(cloudscraper.head(''));
|
||||
expectType<Cloudscraper>(cloudscraper.patch(''));
|
||||
|
||||
// eslint-disable-next-line promise/always-return
|
||||
expectType<Promise<any>>(cloudscraper.get({ uri: '' }).then(noop));
|
||||
expectType<Promise<any>>(cloudscraper.get({ uri: '' }).catch(noop));
|
||||
expectType<Promise<any>>(cloudscraper.get({ uri: '' }).finally(noop));
|
||||
expectType<Promise<any>>(cloudscraper.get({ uri: '' }).promise());
|
||||
expectType<void>(cloudscraper.get({ uri: '' }).cancel());
|
||||
|
||||
expectType<CaptchaHandler>((options: Options, response: CaptchaResponse) => {
|
||||
expectType<Options>(options);
|
||||
expectType<CaptchaResponse>(response);
|
||||
|
||||
const { captcha, isCaptcha } = response;
|
||||
|
||||
expectType<Captcha>(captcha);
|
||||
expectType<true>(isCaptcha);
|
||||
|
||||
expectType<Captcha>({
|
||||
url: '', // <- deprecated
|
||||
uri: new URL(''),
|
||||
siteKey: '',
|
||||
submit: captcha.submit,
|
||||
form: { s: '' }
|
||||
});
|
||||
|
||||
captcha.submit();
|
||||
});
|
||||
|
||||
expectType<DefaultOptions>(cloudscraper.defaultParams);
|
||||
expectType<DefaultOptions>({
|
||||
requester: request,
|
||||
cloudflareMaxTimeout: 0,
|
||||
challengesToSolve: 0,
|
||||
decodeEmails: false,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
onCaptcha: (options: Options, response: CaptchaResponse) => {}
|
||||
});
|
||||
|
||||
expectType<CoreOptions>({
|
||||
requester: request,
|
||||
cloudflareMaxTimeout: 0,
|
||||
challengesToSolve: 0,
|
||||
decodeEmails: false,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
onCaptcha: (options: Options, response: CaptchaResponse) => {},
|
||||
realEncoding: 'utf-8'
|
||||
});
|
20
package.json
20
package.json
|
@ -9,12 +9,15 @@
|
|||
"files": [
|
||||
"lib/",
|
||||
"index.js",
|
||||
"errors.js"
|
||||
"index.d.ts",
|
||||
"errors.js",
|
||||
"errors.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "npm run lint && nyc --reporter=html --reporter=text mocha",
|
||||
"test": "npm run lint && npm run test:typescript && nyc --reporter=html --reporter=text mocha",
|
||||
"test:typescript": "tsc *.ts --noEmit && tsd",
|
||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||
"lint": "eslint --ext .json --ext .js ."
|
||||
"lint": "eslint --ext .json --ext .js --ext .ts ."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -41,6 +44,9 @@
|
|||
"request-promise": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/request-promise": "^4.1.44",
|
||||
"@typescript-eslint/eslint-plugin": "^2.3.1",
|
||||
"@typescript-eslint/parser": "^2.3.1",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"coveralls": "^3.0.3",
|
||||
|
@ -55,10 +61,12 @@
|
|||
"mocha": "^6.1.1",
|
||||
"nyc": "^14.0.0",
|
||||
"sinon": "^7.2.4",
|
||||
"sinon-chai": "^3.3.0"
|
||||
"sinon-chai": "^3.3.0",
|
||||
"tsd": "^0.8.0",
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"request": "^2.88.0",
|
||||
"brotli": "^1.3.2"
|
||||
"brotli": "^1.3.2",
|
||||
"request": "^2.88.0"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue