reduct-js
Version:
ReductStore Client SDK for Javascript/NodeJS/Typescript
258 lines (257 loc) • 9.29 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isCompatibale = exports.Client = void 0;
/**
* Represents HTTP Client for ReductStore API
* @class
*/
const ServerInfo_1 = require("./messages/ServerInfo");
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const axios_1 = __importStar(require("axios"));
const APIError_1 = require("./APIError");
const BucketInfo_1 = require("./messages/BucketInfo");
const BucketSettings_1 = require("./messages/BucketSettings");
const Bucket_1 = require("./Bucket");
const Token_1 = require("./messages/Token");
const stream_1 = require("stream");
const buffer_1 = require("buffer");
const ReplicationInfo_1 = require("./messages/ReplicationInfo");
const ReplicationSettings_1 = require("./messages/ReplicationSettings");
const https = __importStar(require("https"));
class Client {
/**
* HTTP Client for ReductStore
* @param url URL to the storage
* @param options
*/
constructor(url, options = {}) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const bigJson = require("json-bigint")({
alwaysParseAsBig: false,
useNativeBigInt: true,
});
// http client with big int support in JSON
const axiosConfig = {
baseURL: `${url}/api/v1`,
timeout: options.timeout,
headers: {
Authorization: `Bearer ${options.apiToken}`,
},
maxContentLength: Infinity,
maxBodyLength: Infinity,
transformRequest: [
(data) => {
// very ugly hack to support big int in JSON
if (typeof data !== "object" ||
data instanceof stream_1.Readable ||
data instanceof buffer_1.Buffer) {
return data;
}
return bigJson.stringify(data);
},
],
transformResponse: [
(data) => {
// very ugly hack to support big int in JSON
if (typeof data !== "string") {
return data;
}
if (data.length == 0) {
return {};
}
return bigJson.parse(data);
},
],
};
if (typeof window === "undefined") {
axiosConfig.httpsAgent = new https.Agent({
rejectUnauthorized: options.verifySSL !== false,
});
}
this.httpClient = axios_1.default.create(axiosConfig);
this.httpClient.interceptors.response.use((response) => response, async (error) => {
if (error instanceof axios_1.AxiosError) {
throw APIError_1.APIError.from(error);
}
throw error;
});
}
/**
* Get server information
* @async
* @return {Promise<ServerInfo>} the data about the server
*/
async getInfo() {
const { data } = await this.httpClient.get("/info");
return ServerInfo_1.ServerInfo.parse(data);
}
/**
* Get list of buckets
* @async
* @return {BucketInfo[]}
* @see BucketInfo
*/
async getBucketList() {
const { data } = await this.httpClient.get("/list");
return data.buckets.map((bucket) => BucketInfo_1.BucketInfo.parse(bucket));
}
/**
* Create a new bucket
* @param name name of the bucket
* @param settings optional settings
* @return {Promise<Bucket>}
*/
async createBucket(name, settings) {
await this.httpClient.post(`/b/${name}`, settings ? BucketSettings_1.BucketSettings.serialize(settings) : undefined);
return new Bucket_1.Bucket(name, this.httpClient);
}
/**
* Get a bucket by name
* @param name name of the bucket
* @return {Promise<Bucket>}
*/
async getBucket(name) {
await this.httpClient.get(`/b/${name}`);
return new Bucket_1.Bucket(name, this.httpClient);
}
/**
* Try to create a bucket and get it if it already exists
* @param name name of the bucket
* @param settings optional settings
* @return {Promise<Bucket>}
*/
async getOrCreateBucket(name, settings) {
try {
return await this.createBucket(name, settings);
}
catch (error) {
if (error instanceof APIError_1.APIError && error.status === 409) {
return await this.getBucket(name);
}
throw error; // pass exception forward
}
}
/**
* Create a new access token
* @param name name of the token
* @param permissions permissions for the token
* @return {Promise<string>} the token
*
* @example
* const token = await client.createToken("my-token", {fullAccess: true});
* const client = new Client("https://play.storage-reduct.dev", {apiToken: token});
*/
async createToken(name, permissions) {
const { data } = await this.httpClient.post(`/tokens/${name}`, Token_1.TokenPermissions.serialize(permissions));
return data.value;
}
/**
* Get a token by name
* @param name name of the token
* @return {Promise<Token>} the token
*/
async getToken(name) {
const { data } = await this.httpClient.get(`/tokens/${name}`);
return Token_1.Token.parse(data);
}
/**
* List all tokens
* @return {Promise<Token[]>} the list of tokens
*/
async getTokenList() {
const { data } = await this.httpClient.get("/tokens");
return data.tokens.map((token) => Token_1.Token.parse(token));
}
/**
* Delete a token by name
* @param name name of the token
*/
async deleteToken(name) {
await this.httpClient.delete(`/tokens/${name}`);
}
/**
* Get current API token and its permissions
* @return {Promise<Token>} the token
*/
async me() {
const { data } = await this.httpClient.get("/me");
return Token_1.Token.parse(data);
}
/**
* Get the list of replications
* @return {Promise<ReplicationInfo[]>} the list of replications
*/
async getReplicationList() {
const { data } = (await this.httpClient.get("/replications"));
return data.replications.map((replication) => ReplicationInfo_1.ReplicationInfo.parse(replication));
}
/**
* Get full information about a replication
* @param name name of the replication
* @return {Promise<FullReplicationInfo>} the replication
*/
async getReplication(name) {
const { data } = await this.httpClient.get(`/replications/${name}`);
return ReplicationInfo_1.FullReplicationInfo.parse(data);
}
/**
* Create a new replication
* @param name name of the replication
* @param settings settings of the replication
* @return {Promise<void>}
*/
async createReplication(name, settings) {
await this.httpClient.post(`/replications/${name}`, ReplicationSettings_1.ReplicationSettings.serialize(settings));
}
/**
* Update a replication
* @param name name of the replication
* @param settings settings of the replication
* @return {Promise<void>}
*/
async updateReplication(name, settings) {
await this.httpClient.put(`/replications/${name}`, ReplicationSettings_1.ReplicationSettings.serialize(settings));
}
/**
* Delete a replication
* @param name name of the replication
* @return {Promise<void>}
*/
async deleteReplication(name) {
await this.httpClient.delete(`/replications/${name}`);
}
}
exports.Client = Client;
const isCompatibale = (min_version, current_version) => {
if (min_version === undefined || current_version === undefined) {
return false;
}
const [a_major, a_minor] = min_version.split(".").map((v) => parseInt(v));
const [b_major, b_minor] = current_version.split(".").map((v) => parseInt(v));
return a_major === b_major && a_minor <= b_minor;
};
exports.isCompatibale = isCompatibale;