UNPKG

@codex-storage/sdk-js

Version:

Codex SDK to interact with the Codex decentralized storage network.

784 lines (770 loc) 23.5 kB
'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