@codex-storage/sdk-js
Version:
Codex SDK to interact with the Codex decentralized storage network.
784 lines (770 loc) • 23.5 kB
JavaScript
'use strict';
var v = require('valibot');
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var v__namespace = /*#__PURE__*/_interopNamespace(v);
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// src/api/config.ts
var Api;
var init_config = __esm({
"src/api/config.ts"() {
Api = {
config: {
prefix: "/api/codex/v1"
}
};
}
});
exports.CodexError = void 0; exports.CodexValibotIssuesMap = void 0;
var init_errors = __esm({
"src/errors/errors.ts"() {
exports.CodexError = class extends Error {
code;
errors;
sourceStack;
constructor(message, { code, errors, sourceStack } = {}) {
super(message);
this.code = code || null;
this.errors = errors || null;
this.sourceStack = sourceStack || null;
}
};
exports.CodexValibotIssuesMap = (issues) => issues.map((i) => {
var _a;
return {
expected: i.expected,
received: i.received,
message: i.message,
path: (_a = i.path) == null ? void 0 : _a.map((item) => item.key).join(".")
};
});
}
});
// src/promise-safe/promise-safe.ts
var Promises;
var init_promise_safe = __esm({
"src/promise-safe/promise-safe.ts"() {
init_errors();
Promises = {
async safe(promise) {
try {
const result = await promise();
return { error: false, data: result };
} catch (e) {
return {
error: true,
data: new exports.CodexError(e instanceof Error ? e.message : "" + e, {
sourceStack: e instanceof Error ? e.stack || null : null
})
};
}
}
};
}
});
// src/values/values.ts
var init_values = __esm({
"src/values/values.ts"() {
init_errors();
}
});
// src/fetch-safe/fetch-safe.ts
exports.FetchAuthBuilder = void 0; exports.Fetch = void 0;
var init_fetch_safe = __esm({
"src/fetch-safe/fetch-safe.ts"() {
init_errors();
init_promise_safe();
init_values();
exports.FetchAuthBuilder = {
build(auth) {
if (auth == null ? void 0 : auth.basic) {
return {
Authorization: "Basic " + auth.basic
};
}
return {};
}
};
exports.Fetch = {
async safe(url, init) {
const res = await Promises.safe(() => fetch(url, init));
if (res.error) {
return {
error: true,
data: new exports.CodexError(res.data.message, {
code: 502
})
};
}
if (!res.data.ok) {
const message = await Promises.safe(() => res.data.text());
if (message.error) {
return message;
}
return {
error: true,
data: new exports.CodexError(message.data, {
code: res.data.status
})
};
}
return { error: false, data: res.data };
},
async safeJson(url, init) {
const res = await this.safe(url, init);
if (res.error) {
return res;
}
return Promises.safe(() => res.data.json());
},
async safeText(url, init) {
const res = await this.safe(url, init);
if (res.error) {
return res;
}
return Promises.safe(() => res.data.text());
}
};
}
});
exports.CodexCreateAvailabilityInput = void 0; exports.CodexAvailabilityPatchInput = void 0; exports.CodexCreateStorageRequestInput = void 0;
var init_types = __esm({
"src/marketplace/types.ts"() {
exports.CodexCreateAvailabilityInput = v__namespace.strictObject({
totalSize: v__namespace.pipe(v__namespace.number(), v__namespace.minValue(1)),
duration: v__namespace.pipe(v__namespace.number(), v__namespace.minValue(1)),
minPricePerBytePerSecond: v__namespace.number(),
totalCollateral: v__namespace.number(),
enabled: v__namespace.optional(v__namespace.boolean()),
until: v__namespace.optional(v__namespace.number())
});
exports.CodexAvailabilityPatchInput = v__namespace.strictObject({
id: v__namespace.string(),
totalSize: v__namespace.pipe(v__namespace.number(), v__namespace.minValue(1)),
duration: v__namespace.pipe(v__namespace.number(), v__namespace.minValue(1)),
minPricePerBytePerSecond: v__namespace.number(),
totalCollateral: v__namespace.number(),
enabled: v__namespace.optional(v__namespace.boolean()),
until: v__namespace.optional(v__namespace.number())
});
exports.CodexCreateStorageRequestInput = v__namespace.strictObject({
cid: v__namespace.string(),
duration: v__namespace.pipe(v__namespace.number(), v__namespace.minValue(1)),
pricePerBytePerSecond: v__namespace.number(),
proofProbability: v__namespace.number(),
nodes: v__namespace.optional(v__namespace.number(), 1),
tolerance: v__namespace.optional(v__namespace.number(), 0),
expiry: v__namespace.pipe(v__namespace.number(), v__namespace.minValue(1)),
collateralPerByte: v__namespace.number()
});
}
});
// src/marketplace/marketplace.ts
var marketplace_exports = {};
__export(marketplace_exports, {
CodexMarketplace: () => exports.CodexMarketplace
});
exports.CodexMarketplace = void 0;
var init_marketplace = __esm({
"src/marketplace/marketplace.ts"() {
init_config();
init_errors();
init_fetch_safe();
init_types();
init_types();
exports.CodexMarketplace = class {
url;
auth = {};
constructor(url, options) {
this.url = url;
if (options == null ? void 0 : options.auth) {
this.auth = options.auth;
}
}
/**
* Returns active slots
*/
async activeSlots() {
const url = this.url + Api.config.prefix + "/sales/slots";
return exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
/**
* Returns active slot with id {slotId} for the host
*/
async activeSlot(slotId) {
const url = this.url + Api.config.prefix + "/sales/slots/" + slotId;
return exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
transformAvailability({
freeSize,
...a
}) {
const availability = {
...a,
minPricePerBytePerSecond: parseInt(a.minPricePerBytePerSecond, 10),
totalCollateral: parseInt(a.totalCollateral, 10),
totalRemainingCollateral: parseInt(a.totalRemainingCollateral, 10)
};
if (freeSize) {
availability.freeSize = freeSize;
}
return availability;
}
/**
* Returns storage that is for sale
*/
async availabilities() {
const url = this.url + Api.config.prefix + "/sales/availability";
const res = await exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
if (res.error) {
return res;
}
return {
error: false,
data: res.data.map(this.transformAvailability)
};
}
/**
* Offers storage for sale
*/
async createAvailability(input) {
const result = v__namespace.safeParse(exports.CodexCreateAvailabilityInput, input);
if (!result.success) {
return {
error: true,
data: new exports.CodexError("Cannot validate the input", {
errors: exports.CodexValibotIssuesMap(result.issues)
})
};
}
const url = this.url + Api.config.prefix + "/sales/availability";
const body = {
totalSize: result.output.totalSize,
duration: result.output.duration,
minPricePerBytePerSecond: result.output.minPricePerBytePerSecond.toString(),
totalCollateral: result.output.totalCollateral.toString()
};
if (result.output.enabled) {
body.enabled = result.output.enabled;
}
if (result.output.until) {
body.until = result.output.until;
}
return exports.Fetch.safeJson(url, {
method: "POST",
headers: exports.FetchAuthBuilder.build(this.auth),
body: JSON.stringify(body)
}).then((result2) => {
if (result2.error) {
return result2;
}
return { error: false, data: this.transformAvailability(result2.data) };
});
}
/**
* The new parameters will be only considered for new requests.
* Existing Requests linked to this Availability will continue as is.
*/
async updateAvailability(input) {
const result = v__namespace.safeParse(exports.CodexAvailabilityPatchInput, input);
if (!result.success) {
return {
error: true,
data: new exports.CodexError("Cannot validate the input", {
errors: exports.CodexValibotIssuesMap(result.issues)
})
};
}
const url = this.url + Api.config.prefix + "/sales/availability/" + result.output.id;
const body = {
totalSize: result.output.totalSize,
duration: result.output.duration,
minPricePerBytePerSecond: result.output.minPricePerBytePerSecond.toString(),
totalCollateral: result.output.totalCollateral.toString()
};
if (result.output.enabled) {
body.enabled = result.output.enabled;
}
if (result.output.until) {
body.until = result.output.until;
}
const res = await exports.Fetch.safe(url, {
method: "PATCH",
headers: exports.FetchAuthBuilder.build(this.auth),
body: JSON.stringify(body)
});
if (res.error) {
return res;
}
return { error: false, data: "" };
}
/**
* Return's list of Reservations for ongoing Storage Requests that the node hosts.
*/
async reservations(availabilityId) {
const url = this.url + Api.config.prefix + `/sales/availability/${availabilityId}/reservations`;
return exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
/**
* Returns list of purchase IDs
*/
async purchaseIds() {
const url = this.url + Api.config.prefix + `/storage/purchases`;
return exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
transformPurchase(p) {
const purchase = {
requestId: p.requestId,
state: p.state
};
if (p.error) {
purchase.error = p.error;
}
if (!p.request) {
return purchase;
}
return {
...purchase,
request: {
...p.request,
ask: {
...p.request.ask,
proofProbability: parseInt(p.request.ask.proofProbability, 10),
pricePerBytePerSecond: parseInt(
p.request.ask.pricePerBytePerSecond,
10
)
}
}
};
}
async purchases() {
const res = await this.purchaseIds();
if (res.error) {
return res;
}
const promises = [];
for (const id of res.data) {
promises.push(this.purchaseDetail(id));
}
const purchases = await Promise.all(promises);
return {
error: false,
data: purchases.map(
(p) => p.error ? {
state: "error",
error: p.data.message,
requestId: ""
} : p.data
)
};
}
/**
* Returns purchase details
*/
async purchaseDetail(purchaseId) {
const url = this.url + Api.config.prefix + `/storage/purchases/` + purchaseId;
return exports.Fetch.safeJson(url, {
headers: exports.FetchAuthBuilder.build(this.auth),
method: "GET"
}).then((res) => {
if (res.error) {
return res;
}
return { error: false, data: this.transformPurchase(res.data) };
});
}
/**
* Creates a new request for storage.
*/
async createStorageRequest(input) {
const result = v__namespace.safeParse(exports.CodexCreateStorageRequestInput, input);
if (!result.success) {
return {
error: true,
data: new exports.CodexError("Cannot validate the input", {
errors: exports.CodexValibotIssuesMap(result.issues)
})
};
}
const {
cid,
duration,
pricePerBytePerSecond,
proofProbability,
nodes,
collateralPerByte,
expiry,
tolerance
} = result.output;
const url = this.url + Api.config.prefix + "/storage/request/" + cid;
return exports.Fetch.safeText(url, {
method: "POST",
headers: exports.FetchAuthBuilder.build(this.auth),
body: JSON.stringify({
duration,
pricePerBytePerSecond: pricePerBytePerSecond.toString(),
proofProbability: proofProbability.toString(),
nodes,
collateralPerByte: collateralPerByte.toString(),
expiry,
tolerance
})
});
}
};
}
});
exports.CodexLogLevelInput = void 0;
var init_types2 = __esm({
"src/debug/types.ts"() {
exports.CodexLogLevelInput = v__namespace.picklist([
"TRACE",
"DEBUG",
"INFO",
"NOTICE",
"WARN",
"ERROR",
"FATAL"
]);
}
});
// src/debug/debug.ts
var debug_exports = {};
__export(debug_exports, {
CodexDebug: () => exports.CodexDebug
});
exports.CodexDebug = void 0;
var init_debug = __esm({
"src/debug/debug.ts"() {
init_config();
init_errors();
init_fetch_safe();
init_types2();
exports.CodexDebug = class {
url;
auth = {};
constructor(url, options) {
this.url = url;
if (options == null ? void 0 : options.auth) {
this.auth = options.auth;
}
}
/**
* Set log level at run time
*/
async setLogLevel(level) {
const result = v__namespace.safeParse(exports.CodexLogLevelInput, level);
if (!result.success) {
return Promise.resolve({
error: true,
data: new exports.CodexError("Cannot validate the input", {
errors: exports.CodexValibotIssuesMap(result.issues)
})
});
}
const url = this.url + Api.config.prefix + "/debug/chronicles/loglevel?level=" + level;
return exports.Fetch.safeText(url, {
method: "POST",
headers: exports.FetchAuthBuilder.build(this.auth),
body: ""
});
}
/**
* Gets node information
*/
info() {
const url = this.url + Api.config.prefix + `/debug/info`;
return exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
};
}
});
// src/data/data.ts
var data_exports = {};
__export(data_exports, {
CodexData: () => exports.CodexData
});
exports.CodexData = void 0;
var init_data = __esm({
"src/data/data.ts"() {
init_config();
init_fetch_safe();
exports.CodexData = class {
url;
auth = {};
constructor(url, options) {
this.url = url;
if (options == null ? void 0 : options.auth) {
this.auth = options.auth;
}
}
/**
* Lists manifest CIDs stored locally in node.
* TODO: remove the faker data part when the api is ready
*/
cids() {
const url = this.url + Api.config.prefix + "/data";
return exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
}).then((data) => {
if (data.error) {
return data;
}
return { error: false, data: { content: data.data.content } };
});
}
/**
* Gets a summary of the storage space allocation of the node.
*/
space() {
const url = this.url + Api.config.prefix + "/space";
return exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
/**
* Upload a file in a streaming manner.
* Once completed, the file is stored in the node and can be retrieved by any node in the network using the returned CID.
* XMLHttpRequest is used instead of fetch for this case, to obtain progress information.
* A callback onProgress can be passed to receive upload progress data information.
*/
upload(stategy) {
const url = this.url + Api.config.prefix + "/data";
return {
result: stategy.upload(url, { auth: this.auth }),
abort: () => {
stategy.abort();
}
};
}
/**
* Download a file from the local node in a streaming manner.
* If the file is not available locally, a 404 is returned.
*/
async localDownload(cid) {
const url = this.url + Api.config.prefix + "/data/" + cid;
return exports.Fetch.safe(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
/**
* Download a file from the network to the local node if it's not available locally.
* Note: Download is performed async. Call can return before download is completed.
*/
async networkDownload(cid) {
const url = this.url + Api.config.prefix + `/data/${cid}/network`;
return exports.Fetch.safeJson(url, {
method: "POST",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
/**
* Download a file from the network in a streaming manner.
* If the file is not available locally, it will be retrieved from other nodes in the network if able.
*/
async networkDownloadStream(cid) {
const url = this.url + Api.config.prefix + `/data/${cid}/network/stream`;
return exports.Fetch.safe(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
/**
* Download only the dataset manifest from the network to the local node
* if it's not available locally.
*/
async fetchManifest(cid) {
const url = this.url + Api.config.prefix + `/data/${cid}/network/manifest`;
return exports.Fetch.safeJson(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
};
}
});
// src/node/node.ts
var node_exports = {};
__export(node_exports, {
CodexNode: () => exports.CodexNode
});
exports.CodexNode = void 0;
var init_node = __esm({
"src/node/node.ts"() {
init_config();
init_fetch_safe();
exports.CodexNode = class {
url;
auth = {};
constructor(url, options) {
this.url = url;
if (options == null ? void 0 : options.auth) {
this.auth = options.auth;
}
}
/**
* Connect to a peer
*/
connect(peerId, addrs = []) {
const params = new URLSearchParams();
for (const addr of addrs) {
params.append("addrs", addr);
}
const url = this.url + Api.config.prefix + `/connect/${peerId}?` + params.toString();
return exports.Fetch.safeText(url, {
method: "GET",
headers: exports.FetchAuthBuilder.build(this.auth)
});
}
/**
* Get Node's SPR
*/
async spr(type = "json") {
const url = this.url + Api.config.prefix + "/spr";
if (type === "json") {
return exports.Fetch.safeJson(url, {
method: "GET",
headers: {
...exports.FetchAuthBuilder.build(this.auth),
"Content-Type": "application/json"
}
});
}
return exports.Fetch.safeText(url, {
method: "GET",
headers: {
...exports.FetchAuthBuilder.build(this.auth),
"Content-Type": "text/plain"
}
});
}
/**
* Get Node's PeerID
*/
peerId(type = "json") {
const url = this.url + Api.config.prefix + "/node/peerid";
if (type === "json") {
return exports.Fetch.safeJson(url, {
method: "GET",
headers: {
...exports.FetchAuthBuilder.build(this.auth),
"Content-Type": "application/json"
}
});
}
return exports.Fetch.safeText(url, {
method: "GET",
headers: {
...exports.FetchAuthBuilder.build(this.auth),
"Content-Type": "text/plain"
}
});
}
};
}
});
// src/async.ts
init_marketplace();
init_fetch_safe();
init_types();
init_types2();
init_values();
init_errors();
init_debug();
init_data();
init_node();
init_marketplace();
var Codex = class {
url;
_marketplace;
_data;
_node;
_debug;
constructor(url) {
this.url = url;
this._marketplace = null;
this._data = null;
this._node = null;
this._debug = null;
}
async marketplace() {
if (this._marketplace) {
return this._marketplace;
}
const module = await Promise.resolve().then(() => (init_marketplace(), marketplace_exports));
this._marketplace = new module.CodexMarketplace(this.url);
return this._marketplace;
}
async data() {
if (this._data) {
return this._data;
}
const module = await Promise.resolve().then(() => (init_data(), data_exports));
this._data = new module.CodexData(this.url);
return this._data;
}
async node() {
if (this._node) {
return this._node;
}
const module = await Promise.resolve().then(() => (init_node(), node_exports));
this._node = new module.CodexNode(this.url);
return this._node;
}
async debug() {
if (this._debug) {
return this._debug;
}
const module = await Promise.resolve().then(() => (init_debug(), debug_exports));
this._debug = new module.CodexDebug(this.url);
return this._debug;
}
};
exports.Codex = Codex;
//# sourceMappingURL=async.js.map
//# sourceMappingURL=async.js.map