UNPKG

askexperts

Version:

AskExperts SDK: build and use AI experts - ask them questions and pay with bitcoin on an open protocol

512 lines 21 kB
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _DBRemoteClient_token; import { debugDB, debugError } from "../common/debug.js"; import { createAuthToken } from "../common/auth.js"; import { bytesToHex } from "nostr-tools/utils"; export class DBRemoteClient { /** * Creates a new DBRemoteClient instance * @param options - Configuration options for the client */ constructor(options) { _DBRemoteClient_token.set(this, void 0); // Ensure the URL doesn't end with a slash this.baseUrl = options.url || 'https://api.askexperts.io'; this.baseUrl = this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl; this.privateKey = options.privateKey; __classPrivateFieldSet(this, _DBRemoteClient_token, options.token, "f"); debugDB(`Connecting to remote DB server at ${options.url}`); } /** * Create request headers with authentication if privateKey is provided * @param method - HTTP method for the request * @param url - URL for the request * @returns Headers object with authentication if available */ async createHeaders(method, url, bodyString) { const headers = { "Content-Type": "application/json", }; // Add token-based authentication if token is provided if (__classPrivateFieldGet(this, _DBRemoteClient_token, "f")) { // If token is a callback function, call it to get the actual token const tokenValue = typeof __classPrivateFieldGet(this, _DBRemoteClient_token, "f") === 'function' ? await __classPrivateFieldGet(this, _DBRemoteClient_token, "f").call(this) : __classPrivateFieldGet(this, _DBRemoteClient_token, "f"); headers["Authorization"] = `Bearer ${tokenValue}`; } // Otherwise use privateKey-based authentication if available else if (this.privateKey) { const authToken = createAuthToken(this.privateKey, url, method, bodyString); headers["Authorization"] = authToken; } return headers; } get token() { return __classPrivateFieldGet(this, _DBRemoteClient_token, "f"); } set token(value) { __classPrivateFieldSet(this, _DBRemoteClient_token, value, "f"); } /** * List all wallets * @returns Promise resolving to an array of wallet objects */ async listWallets() { try { const url = `${this.baseUrl}/wallets`; const headers = await this.createHeaders("GET", url); const response = await fetch(url, { headers }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to list wallets: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } return await response.json(); } catch (error) { debugError("Error in DBRemoteClient.listWallets:", error); throw error; } } /** * List wallets by specific IDs * @param ids - Array of wallet IDs to retrieve * @returns Promise resolving to an array of wallet objects matching the provided IDs */ async listWalletsByIds(ids) { try { if (!ids.length) { return []; } // For now, we'll fetch all wallets and filter them client-side // In a future implementation, this could be optimized with a dedicated endpoint const allWallets = await this.listWallets(); return allWallets.filter((wallet) => ids.includes(wallet.id)); } catch (error) { debugError("Error in DBRemoteClient.listWalletsByIds:", error); throw error; } } /** * Get a wallet by ID * @param id - ID of the wallet to get * @returns Promise resolving to the wallet if found, null otherwise */ async getWallet(id) { try { const url = `${this.baseUrl}/wallets/${id}`; const headers = await this.createHeaders("GET", url); const response = await fetch(url, { headers }); if (response.status === 404) { return null; } if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to get wallet: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } return await response.json(); } catch (error) { debugError(`Error in DBRemoteClient.getWallet(${id}):`, error); throw error; } } /** * Get a wallet by name * @param name - Name of the wallet to get * @returns Promise resolving to the wallet if found, null otherwise */ async getWalletByName(name) { try { const url = `${this.baseUrl}/wallets/name/${encodeURIComponent(name)}`; const headers = await this.createHeaders("GET", url); const response = await fetch(url, { headers }); if (response.status === 404) { return null; } if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to get wallet by name: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } return await response.json(); } catch (error) { debugError(`Error in DBRemoteClient.getWalletByName(${name}):`, error); throw error; } } /** * Get the default wallet * @returns Promise resolving to the default wallet if found, null otherwise */ async getDefaultWallet() { try { const url = `${this.baseUrl}/wallets/default`; const headers = await this.createHeaders("GET", url); const response = await fetch(url, { headers }); if (response.status === 404) { return null; } if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to get default wallet: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } return await response.json(); } catch (error) { debugError("Error in DBRemoteClient.getDefaultWallet:", error); throw error; } } /** * Insert a new wallet * @param wallet - Wallet to insert (without id) * @returns Promise resolving to the ID of the inserted wallet */ async insertWallet(wallet) { try { const url = `${this.baseUrl}/wallets`; const bodyString = JSON.stringify(wallet); const headers = await this.createHeaders("POST", url, bodyString); const response = await fetch(url, { method: "POST", headers, body: bodyString, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to insert wallet: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } const result = await response.json(); return result.id; } catch (error) { debugError("Error in DBRemoteClient.insertWallet:", error); throw error; } } /** * Update an existing wallet * @param wallet - Wallet to update * @returns Promise resolving to true if wallet was updated, false otherwise */ async updateWallet(wallet) { try { const url = `${this.baseUrl}/wallets/${wallet.id}`; const bodyString = JSON.stringify(wallet); const headers = await this.createHeaders("PUT", url, bodyString); const response = await fetch(url, { method: "PUT", headers, body: bodyString, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); debugError(`Failed to update wallet: ${response.status} ${response.statusText} - ${errorData.message || ""}`); return false; } const result = await response.json(); return result.success === true; } catch (error) { debugError(`Error in DBRemoteClient.updateWallet(${wallet.id}):`, error); return false; } } /** * Delete a wallet * @param id - ID of the wallet to delete * @returns Promise resolving to true if wallet was deleted, false otherwise */ async deleteWallet(id) { try { const url = `${this.baseUrl}/wallets/${id}`; const headers = await this.createHeaders("DELETE", url); const response = await fetch(url, { method: "DELETE", headers, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); debugError(`Failed to delete wallet: ${response.status} ${response.statusText} - ${errorData.message || ""}`); return false; } const result = await response.json(); return result.success === true; } catch (error) { debugError(`Error in DBRemoteClient.deleteWallet(${id}):`, error); return false; } } /** * List all experts * @returns Promise resolving to an array of expert objects */ async listExperts() { try { const url = `${this.baseUrl}/experts`; const headers = await this.createHeaders("GET", url); const response = await fetch(url, { headers }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to list experts: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } return await response.json(); } catch (error) { debugError("Error in DBRemoteClient.listExperts:", error); throw error; } } /** * List experts by specific IDs * @param ids - Array of expert pubkeys to retrieve * @returns Promise resolving to an array of expert objects matching the provided IDs */ async listExpertsByIds(ids) { try { if (!ids.length) { return []; } // For now, we'll fetch all experts and filter them client-side // In a future implementation, this could be optimized with a dedicated endpoint const allExperts = await this.listExperts(); return allExperts.filter((expert) => ids.includes(expert.pubkey)); } catch (error) { debugError("Error in DBRemoteClient.listExpertsByIds:", error); throw error; } } /** * List experts with timestamp newer than the provided timestamp * @param timestamp - Only return experts with timestamp newer than this * @param limit - Maximum number of experts to return (default: 1000) * @returns Promise resolving to an array of expert objects */ async listExpertsAfter(timestamp, limit = 1000) { try { const url = `${this.baseUrl}/experts/after/${timestamp}?limit=${limit}`; const headers = await this.createHeaders("GET", url); const response = await fetch(url, { headers }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to list experts after timestamp: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } return await response.json(); } catch (error) { debugError(`Error in DBRemoteClient.listExpertsAfter(${timestamp}):`, error); throw error; } } /** * Get an expert by pubkey * @param pubkey - Pubkey of the expert to get * @returns Promise resolving to the expert if found, null otherwise */ async getExpert(pubkey) { try { const url = `${this.baseUrl}/experts/${pubkey}`; const headers = await this.createHeaders("GET", url); const response = await fetch(url, { headers }); if (response.status === 404) { return null; } if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to get expert: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } return await response.json(); } catch (error) { debugError(`Error in DBRemoteClient.getExpert(${pubkey}):`, error); throw error; } } /** * Insert a new expert * @param expert - Expert to insert * @returns Promise resolving to true if expert was inserted, false otherwise */ async insertExpert(expert) { try { const url = `${this.baseUrl}/experts`; const bodyString = JSON.stringify(expert); const headers = await this.createHeaders("POST", url, bodyString); const response = await fetch(url, { method: "POST", headers, body: bodyString, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); debugError(`Failed to insert expert: ${response.status} ${response.statusText} - ${errorData.message || ""}`); return false; } const result = await response.json(); return result.success === true; } catch (error) { debugError(`Error in DBRemoteClient.insertExpert(${expert.pubkey}):`, error); return false; } } /** * Update an existing expert * @param expert - Expert to update * @returns Promise resolving to true if expert was updated, false otherwise */ async updateExpert(expert) { try { const url = `${this.baseUrl}/experts/${expert.pubkey}`; const bodyString = JSON.stringify(expert); const headers = await this.createHeaders("PUT", url, bodyString); const response = await fetch(url, { method: "PUT", headers, body: bodyString, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); debugError(`Failed to update expert: ${response.status} ${response.statusText} - ${errorData.message || ""}`); return false; } const result = await response.json(); return result.success === true; } catch (error) { debugError(`Error in DBRemoteClient.updateExpert(${expert.pubkey}):`, error); return false; } } /** * Set the disabled status of an expert * @param pubkey - Pubkey of the expert to update * @param disabled - Whether the expert should be disabled * @returns Promise resolving to true if expert was updated, false otherwise */ async setExpertDisabled(pubkey, disabled) { try { const url = `${this.baseUrl}/experts/${pubkey}/disabled`; const bodyString = JSON.stringify({ disabled }); const headers = await this.createHeaders("PUT", url, bodyString); const response = await fetch(url, { method: "PUT", headers, body: bodyString, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); debugError(`Failed to set expert disabled status: ${response.status} ${response.statusText} - ${errorData.message || ""}`); return false; } const result = await response.json(); return result.success === true; } catch (error) { debugError(`Error in DBRemoteClient.setExpertDisabled(${pubkey}, ${disabled}):`, error); return false; } } /** * Delete an expert * @param pubkey - Pubkey of the expert to delete * @returns Promise resolving to true if expert was deleted, false otherwise */ async deleteExpert(pubkey) { try { const url = `${this.baseUrl}/experts/${pubkey}`; const headers = await this.createHeaders("DELETE", url); const response = await fetch(url, { method: "DELETE", headers, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); debugError(`Failed to delete expert: ${response.status} ${response.statusText} - ${errorData.message || ""}`); return false; } const result = await response.json(); return result.success === true; } catch (error) { debugError(`Error in DBRemoteClient.deleteExpert(${pubkey}):`, error); return false; } } /** * Get the current user ID * @returns Promise resolving to the current user ID */ async getUserId() { try { const url = `${this.baseUrl}/whoami`; const headers = await this.createHeaders("GET", url); const response = await fetch(url, { headers }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to get user ID: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } const result = await response.json(); return result.user_id; } catch (error) { debugError("Error in DBRemoteClient.getUserId:", error); throw error; } } /** * Sign up on the remote server * This will create a new user if one doesn't exist for the current pubkey * * @returns Promise resolving to the user ID */ async signup(uploadPrivkey) { try { const url = `${this.baseUrl}/signup`; const body = {}; if (uploadPrivkey) { if (!this.privateKey) throw new Error("Can't signup without privkey"); body.privkey = bytesToHex(this.privateKey); } const bodyString = JSON.stringify(body); const headers = await this.createHeaders("POST", url, bodyString); const response = await fetch(url, { method: "POST", headers, body: bodyString, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`Failed to sign up: ${response.status} ${response.statusText} - ${errorData.message || ""}`); } const result = await response.json(); return result.user_id; } catch (error) { debugError("Error in DBRemoteClient.signup:", error); throw error; } } /** * Symbol.dispose method for releasing resources */ [(_DBRemoteClient_token = new WeakMap(), Symbol.dispose)]() { // No resources to release } } //# sourceMappingURL=DBRemoteClient.js.map