1 | import axios from "axios";
|
2 | import { Readable } from "node:stream";
|
3 | import { HTTPError, ReadError, RequestError } from "./exceptions.js";
|
4 | import { USER_AGENT } from "./version.js";
|
5 | export default class HTTPClient {
|
6 | instance;
|
7 | config;
|
8 | constructor(config = {}) {
|
9 | this.config = config;
|
10 | const { baseURL, defaultHeaders } = config;
|
11 | this.instance = axios.create({
|
12 | baseURL,
|
13 | headers: Object.assign({}, defaultHeaders, {
|
14 | "User-Agent": USER_AGENT,
|
15 | }),
|
16 | });
|
17 | this.instance.interceptors.response.use(res => res, err => Promise.reject(this.wrapError(err)));
|
18 | }
|
19 | async get(url, params) {
|
20 | const res = await this.instance.get(url, { params });
|
21 | return res.data;
|
22 | }
|
23 | async getStream(url, params) {
|
24 | const res = await this.instance.get(url, {
|
25 | params,
|
26 | responseType: "stream",
|
27 | });
|
28 | return res.data;
|
29 | }
|
30 | async post(url, body, config) {
|
31 | const res = await this.instance.post(url, body, {
|
32 | headers: {
|
33 | "Content-Type": "application/json",
|
34 | ...(config && config.headers),
|
35 | },
|
36 | ...config,
|
37 | });
|
38 | return this.responseParse(res);
|
39 | }
|
40 | responseParse(res) {
|
41 | const { responseParser } = this.config;
|
42 | if (responseParser)
|
43 | return responseParser(res);
|
44 | else
|
45 | return res.data;
|
46 | }
|
47 | async put(url, body, config) {
|
48 | const res = await this.instance.put(url, body, {
|
49 | headers: {
|
50 | "Content-Type": "application/json",
|
51 | ...(config && config.headers),
|
52 | },
|
53 | ...config,
|
54 | });
|
55 | return this.responseParse(res);
|
56 | }
|
57 | async postForm(url, body) {
|
58 | const params = new URLSearchParams();
|
59 | for (const key in body) {
|
60 | if (body.hasOwnProperty(key)) {
|
61 | params.append(key, body[key]);
|
62 | }
|
63 | }
|
64 | const res = await this.instance.post(url, params.toString(), {
|
65 | headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
66 | });
|
67 | return res.data;
|
68 | }
|
69 | async postFormMultipart(url, form) {
|
70 | const res = await this.instance.post(url, form);
|
71 | return res.data;
|
72 | }
|
73 | async putFormMultipart(url, form, config) {
|
74 | const res = await this.instance.put(url, form, config);
|
75 | return res.data;
|
76 | }
|
77 | async toBuffer(data) {
|
78 | if (Buffer.isBuffer(data)) {
|
79 | return data;
|
80 | }
|
81 | else if (data instanceof Readable) {
|
82 | return await new Promise((resolve, reject) => {
|
83 | const buffers = [];
|
84 | let size = 0;
|
85 | data.on("data", (chunk) => {
|
86 | buffers.push(chunk);
|
87 | size += chunk.length;
|
88 | });
|
89 | data.on("end", () => resolve(Buffer.concat(buffers, size)));
|
90 | data.on("error", reject);
|
91 | });
|
92 | }
|
93 | else {
|
94 | throw new Error("invalid data type for binary data");
|
95 | }
|
96 | }
|
97 | async postBinary(url, data, contentType) {
|
98 | const buffer = await this.toBuffer(data);
|
99 | const res = await this.instance.post(url, buffer, {
|
100 | headers: {
|
101 | "Content-Type": contentType || "image/png",
|
102 | "Content-Length": buffer.length,
|
103 | },
|
104 | });
|
105 | return res.data;
|
106 | }
|
107 | async postBinaryContent(url, body) {
|
108 | const res = await this.instance.post(url, body, {
|
109 | headers: {
|
110 | "Content-Type": body.type,
|
111 | "Content-Length": body.size,
|
112 | },
|
113 | });
|
114 | return res.data;
|
115 | }
|
116 | async delete(url, params) {
|
117 | const res = await this.instance.delete(url, { params });
|
118 | return res.data;
|
119 | }
|
120 | wrapError(err) {
|
121 | if (err.response) {
|
122 | const { status, statusText } = err.response;
|
123 | const { message } = err;
|
124 | return new HTTPError(message, {
|
125 | statusCode: status,
|
126 | statusMessage: statusText,
|
127 | originalError: err,
|
128 | });
|
129 | }
|
130 | else if (err.code) {
|
131 | const { message, code } = err;
|
132 | return new RequestError(message, { code, originalError: err });
|
133 | }
|
134 | else if (err.config) {
|
135 |
|
136 | const { message } = err;
|
137 | return new ReadError(message, { originalError: err });
|
138 | }
|
139 |
|
140 | return err;
|
141 | }
|
142 | }
|
143 |
|
\ | No newline at end of file |