Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): Add rxjs-axios core #1

Merged
merged 1 commit into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### Dependencies ###
node_modules/
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

### Auto-generated ###
build/
dist/
dist.tar.gz

### Logs ###
*.log
9 changes: 9 additions & 0 deletions .yarn/plugins/@yarnpkg/plugin-engines.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* eslint-disable */
//prettier-ignore
module.exports = {
name: "@yarnpkg/plugin-engines",
factory: function (require) {
var plugin=(()=>{var P=Object.create,m=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var b=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var T=n=>m(n,"__esModule",{value:!0});var i=n=>{if(typeof require!="undefined")return require(n);throw new Error('Dynamic require of "'+n+'" is not supported')};var V=(n,e)=>{for(var r in e)m(n,r,{get:e[r],enumerable:!0})},N=(n,e,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of j(e))!Y.call(n,t)&&t!=="default"&&m(n,t,{get:()=>e[t],enumerable:!(r=R(e,t))||r.enumerable});return n},s=n=>N(T(m(n!=null?P(b(n)):{},"default",n&&n.__esModule&&"default"in n?{get:()=>n.default,enumerable:!0}:{value:n,enumerable:!0})),n);var S={};V(S,{default:()=>$});var o=s(i("@yarnpkg/core")),c;(function(r){r.Yarn="Yarn",r.Console="Console"})(c||(c={}));var h=class{constructor(e){this.throwWrongEngineError=(e,r)=>{let t=this.formatErrorMessage(e,r);this.throwError(t)};this.throwError=e=>{switch(this.errorReporter){case c.Yarn:this.reportYarnError(e);break;case c.Console:default:this.reportConsoleError(e);break}};this.reportYarnError=e=>{throw new o.ReportError(o.MessageName.UNNAMED,e)};this.reportConsoleError=e=>{console.error(e),process.exit(1)};this.formatErrorMessage=(e,r)=>{let{configuration:t}=this.project,p=o.formatUtils.applyStyle(t,o.formatUtils.pretty(t,this.engine,"green"),2),g=o.formatUtils.pretty(t,e,"cyan"),d=o.formatUtils.pretty(t,r,"cyan"),w=`The current ${p} version ${g} does not satisfy the required version ${d}.`;return o.formatUtils.pretty(t,w,"red")};this.project=e.project,this.errorReporter=e.errorReporter}};var f=s(i("fs")),u=s(i("path")),l=s(i("semver")),k=s(i("@yarnpkg/fslib")),a=s(i("@yarnpkg/core"));var v=class extends h{constructor(){super(...arguments);this.resolveNvmRequiredVersion=()=>{let{configuration:e,cwd:r}=this.project,t=(0,u.resolve)(k.npath.fromPortablePath(r),".nvmrc"),p=a.formatUtils.applyStyle(e,a.formatUtils.pretty(e,this.engine,"green"),2);if(!(0,f.existsSync)(t)){this.throwError(a.formatUtils.pretty(e,`Unable to verify the ${p} version. The .nvmrc file does not exist.`,"red"));return}let g=(0,f.readFileSync)(t,"utf-8").trim();if((0,l.validRange)(g))return g;let d=a.formatUtils.pretty(e,".nvmrc","yellow");this.throwError(a.formatUtils.pretty(e,`Unable to verify the ${p} version. The ${d} file contains an invalid semver range.`,"red"))}}get engine(){return"Node"}verifyEngine(e){let r=e.node;r!=null&&(r===".nvmrc"&&(r=this.resolveNvmRequiredVersion()),(0,l.satisfies)(process.version,r,{includePrerelease:!0})||this.throwWrongEngineError(process.version.replace(/^v/i,""),r.replace(/^v/i,"")))}};var x=s(i("semver")),y=s(i("@yarnpkg/core"));var E=class extends h{get engine(){return"Yarn"}verifyEngine(e){let r=e.yarn;r!=null&&((0,x.satisfies)(y.YarnVersion,r,{includePrerelease:!0})||this.throwWrongEngineError(y.YarnVersion,r))}};var C=n=>e=>{let{engines:r={}}=e.getWorkspaceByCwd(e.cwd).manifest.raw,t={project:e,errorReporter:n};[new v(t),new E(t)].forEach(g=>g.verifyEngine(r))},q={hooks:{validateProject:C(c.Yarn),setupScriptEnvironment:C(c.Console)}},$=q;return S;})();
return plugin;
}
};
541 changes: 541 additions & 0 deletions .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs

Large diffs are not rendered by default.

801 changes: 801 additions & 0 deletions .yarn/releases/yarn-3.2.4.cjs

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
nodeLinker: node-modules

plugins:
- path: .yarn/plugins/@yarnpkg/plugin-engines.cjs
spec: "https://raw.githubusercontent.com/devoto13/yarn-plugin-engines/main/bundles/%40yarnpkg/plugin-engines.js"
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"

yarnPath: .yarn/releases/yarn-3.2.4.cjs
41 changes: 41 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "rxjs-axios",
"version": "0.0.0",
"description": "A complete Axios wrapper that uses RxJS observables",
"author": "Jose Luis Leon <[email protected]>",
"private": true,
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist/"
],
"engines": {
"node": ">=16"
},
"scripts": {
"build": "tsc -p tsconfig.prod.json",
"compile": "tsc",
"lint": "tslint -p tsconfig.json -c tslint.json \"**/*.ts\""
},
"devDependencies": {
"@types/node": "^18.11.9",
"axios": "^1.1.3",
"rxjs": "^7.5.7",
"tslint": "^6.1.3",
"typescript": "^4.8.4"
},
"peerDependencies": {
"axios": "~1.1.3",
"rxjs": "~7.5.7"
},
"peerDependenciesMeta": {
"axios": {
"optional": false
},
"rxjs": {
"optional": false
}
},
"packageManager": "[email protected]"
}
51 changes: 51 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import defaultAxios, { AxiosResponse } from "axios";
import { Observable } from "rxjs";

import { RxjsAxios } from "./lib/RxjsAxios";

export type AxiosObservable<T> = Observable<AxiosResponse<T>>;

/**
* Re-export all everithing from axios, except anything to do with promises.
*/
export {
AxiosError,
CanceledError,
type AxiosAdapter,
type AxiosBasicCredentials,
type AxiosDefaults,
type AxiosHeaders,
type AxiosInterceptorManager,
type AxiosInterceptorOptions,
type AxiosProgressEvent,
type AxiosProxyConfig,
type AxiosRequestConfig,
type AxiosRequestHeaders,
type AxiosRequestTransformer,
type AxiosResponse,
type AxiosResponseHeaders,
type AxiosResponseTransformer,
type CreateAxiosDefaults,
type CustomParamsSerializer,
type FormDataVisitorHelpers,
type FormSerializerOptions,
type GenericAbortSignal,
type GenericFormData,
type GenericHTMLFormElement,
type HeadersDefaults,
type HttpStatusCode,
type Method,
type ParamEncoder,
type ParamsSerializerOptions,
type RawAxiosRequestHeaders,
type RawAxiosResponseHeaders,
type ResponseType,
type SerializerOptions,
type SerializerVisitor,
type TransitionalOptions,
type responseEncoding,
} from "axios";
export { RxjsAxios as Axios } from "./lib/RxjsAxios";

export const axios = RxjsAxios.of(defaultAxios);
export default axios;
225 changes: 225 additions & 0 deletions src/lib/RxjsAxios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import axios, {
AxiosDefaults,
AxiosError,
AxiosInstance,
AxiosInterceptorManager,
AxiosRequestConfig,
AxiosResponse, Cancel,
CancelToken,
CancelTokenSource,
CancelTokenStatic,
CreateAxiosDefaults,
FormSerializerOptions,
GenericFormData,
GenericHTMLFormElement,
} from "axios";
import { Observable } from "rxjs";

import { observify } from "./observify";

interface Interceptors {
request: AxiosInterceptorManager<AxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
}

interface Cancellable {
cancelSource: CancelTokenSource;
cancelToken: CancelToken;
}

export class RxjsAxios {

private axios: AxiosInstance;

private CancelToken: CancelTokenStatic;

private constructor(instance: AxiosInstance) {
this.axios = instance;
this.CancelToken = axios.CancelToken;
}

public static of(instance: AxiosInstance): RxjsAxios {
return new RxjsAxios(instance);
}

public static create<D>(config?: CreateAxiosDefaults<D>): RxjsAxios {
const instance = axios.create(config);

return new RxjsAxios(instance);
}

public static isAxiosError<T, D>(error: unknown): error is AxiosError<T, D> {
return axios.isAxiosError<T, D>(error);
}

public static isCancel(error: unknown): error is Cancel {
return axios.isCancel(error);
}

public static toFormData(
sourceObj: object,
targetFormData?: GenericFormData,
options?: FormSerializerOptions,
): GenericFormData {
return axios.toFormData(sourceObj, targetFormData, options);
}

public static formToJSON(form: GenericFormData | GenericHTMLFormElement): object {
return axios.formToJSON(form);
}

public get defaults(): AxiosDefaults {
return this.axios.defaults;
}

public get interceptors(): Interceptors {
return this.axios.interceptors;
}

public request<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
config: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.request<T, R, D>({ ...config, cancelToken }),
cancelSource,
);
}

public get<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.get<T, R, D>(url, { ...config, cancelToken }),
cancelSource,
);
}

public delete<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.delete<T, R, D>(url, { ...config, cancelToken }),
cancelSource,
);
}

public head<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.head<T, R, D>(url, { ...config, cancelToken }),
cancelSource,
);
}

public options<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.options<T, R, D>(url, { ...config, cancelToken }),
cancelSource,
);
}

public post<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.post<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public put<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.put<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public patch<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.patch<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public postForm<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.postForm<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public putForm<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.putForm<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

public patchForm<T, R extends AxiosResponse<T> = AxiosResponse<T>, D = unknown>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
): Observable<R> {
const { cancelSource, cancelToken } = this.makeCancellable();

return observify(
() => this.axios.patchForm<T, R, D>(url, data, { ...config, cancelToken }),
cancelSource,
);
}

private makeCancellable(): Cancellable {
const cancelSource = this.CancelToken.source();
const cancelToken = cancelSource.token;

return {
cancelSource,
cancelToken,
};
}
}
16 changes: 16 additions & 0 deletions src/lib/observify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { AxiosResponse, CancelTokenSource } from "axios";
import { Observable } from "rxjs";

export function observify<T, R extends AxiosResponse<T>>(
makeRequest: () => Promise<R>,
cancelSource: CancelTokenSource,
): Observable<R> {
return new Observable(subscriber => {
makeRequest()
.then(response => subscriber.next(response))
.catch(error => subscriber.error(error))
.finally(() => subscriber.complete());

return { unsubscribe: () => cancelSource.cancel() };
});
}
Loading