metafold.js

import axios from "axios";
import { PollTimeout } from "./error.js";
import { Projects } from "./resources/Projects.js";
import { Assets } from "./resources/Assets.js";
import { Jobs } from "./resources/Jobs.js";
import { Workflows } from "./resources/Workflows.js";
const DEFAULT_BASE_URL = "https://api.metafold3d.com";
/** Metafold REST API client. */
class MetafoldClient {
    projectID;
    /**
     * Endpoint for querying user information.
     * @type {Projects}
     */
    projects;
    /**
     * Endpoint for managing asset resources.
     * @type {Assets}
     */
    assets;
    /**
     * Endpoint for managing job resources.
     * @type {Jobs}
     */
    jobs;
    /**
     * Endpoint for managing workflow resources.
     * @type {Workflows}
     */
    workflows;
    /** Underlying HTTP client. */
    axios;
    get;
    put;
    post;
    patch;
    delete;
    /**
     * Create a client.
     *
     * @param {string} accessToken - Metafold API secret key.
     * @param {string} [projectID] - ID of the project to make API calls against.
     * @param {string} [baseURL] - Metafold API URL. Used for internal testing.
     */
    constructor(accessToken, projectID, baseURL = DEFAULT_BASE_URL) {
        this.projectID = projectID;
        this.axios = axios.create({
            baseURL,
            headers: {
                "Accept": "application/json",
                "Authorization": `Bearer ${accessToken}`,
            },
        });
        this.axios.interceptors.response.use((r) => r, (err) => {
            if (err.response) {
                const r = err.response;
                // Error responses aren't entirely consistent in the Metafold API,
                // for now we check for a handful of possible fields.
                if (r.data.errors) {
                    const msg = r.data.errors.map((e) => {
                        if (e.field) {
                            return `  [${e.field}] ${e.msg}`;
                        }
                        return `  ${e.msg}`;
                    }).join("\n");
                    return Promise.reject(new Error(`Bad request:\n${msg}`, { cause: err }));
                }
                const reason = r.data?.msg ?? r.data?.description;
                return Promise.reject(new Error(`${reason ?? r.statusText}`, { cause: err }));
            }
            return Promise.reject(err);
        });
        this.get = this.axios.get;
        this.put = this.axios.put;
        this.post = this.axios.post;
        this.patch = this.axios.patch;
        this.delete = this.axios.delete;
        this.projects = new Projects(this);
        this.assets = new Assets(this);
        this.jobs = new Jobs(this);
        this.workflows = new Workflows(this);
    }
    /**
     * Poll the given URL every one second.
     *
     * Helpful for waiting on job results given a status URL.
     *
     * @param {string} url - Workflow status url.
     * @param {number} [timeout=12000] - Time in seconds to wait for a result.
     * @param {number} [every=1] - Frequency in seconds.
     * @returns HTTP response.
     */
    poll(url, timeout = 1000 * 60 * 2, every = 1) {
        return new Promise((resolve, reject) => {
            /* eslint-disable prefer-const */
            let intervalID;
            let timeoutID;
            /* eslint-enable prefer-const */
            const clearTimers = () => {
                clearInterval(intervalID);
                clearTimeout(timeoutID);
            };
            intervalID = setInterval(() => {
                this.get(url)
                    .then((r) => {
                    if (r.status === 202) {
                        return;
                    }
                    clearTimers();
                    resolve(r);
                })
                    .catch((e) => {
                    clearTimers();
                    reject(e);
                });
            }, 1000 * every);
            timeoutID = setTimeout(() => {
                clearInterval(intervalID);
                reject(new PollTimeout("Polling timed out"));
            }, timeout);
        });
    }
}
export default MetafoldClient;
export * from "./func.js";
export * from "./func-types.js";