UNPKG

@openstream/client

Version:
587 lines (586 loc) 22.7 kB
import StatusCode from "http-status-codes"; import qs from "qs"; import { ACCESS_TOKEN_HEADER, FORWARD_IP_HEADER } from "./defs/constants.js"; import { ClientError } from "./error.js"; // import type { Logger } from "./logger.js"; import node_fetch, { Headers } from "node-fetch"; export { ClientError }; // import http from "http"; // import https from "https"; // const http_agent = new http.Agent({ keepAlive: false }); // const https_agent = new https.Agent({ keepAlive: false }); const qss = (v) => { return qs.stringify(v, { addQueryPrefix: true, skipNulls: true }); }; export class Client { base_url; node_fetch; // logger: Logger; me; auth; plans; admins; users; accounts; stations; analytics; app_analytics; invitations; payment_methods; stream_connections; stream_connections_lite; constructor(base_url, { /*ogger,*/ fetch = node_fetch } = {}) { this.base_url = base_url.trim().replace(/\/+$/g, ""); // this.logger = logger.scoped("client"); this.node_fetch = fetch; this.me = new Me(this); this.auth = new Auth(this); this.plans = new Plans(this); this.admins = new Admins(this); this.users = new Users(this); this.accounts = new Accounts(this); this.stations = new Stations(this); this.analytics = new Analytics(this); this.app_analytics = new AppAnalytics(this); this.invitations = new AccountInvitations(this); this.payment_methods = new PaymentMethods(this); this.stream_connections = new StreamConnections(this); this.stream_connections_lite = new StreamConnectionsLite(this); } async fetch(_url, init = {}) { const url = `${this.base_url}${_url}`; // const method = init.method ?? "GET"; // this.logger.debug(`fetch: ${method} ${url}`); return await this.node_fetch(url, { ...init }).catch(e => { // this.logger.warn(`fetch error: ${e} | cause=${e.cause}`) console.warn("client fetch failed", e, e.cause ?? null); throw new ClientError(StatusCode.BAD_GATEWAY, "CLIENT_GATEWAY_FETCH", "Gateway unavailable"); }); } async get_json_body(res) { const body = await res.json().catch(e => { // this.logger.warn(`json error: ${e} cause=${e.cause}`) throw new ClientError(StatusCode.BAD_GATEWAY, "CLIENT_GATEWAY_JSON", "Gateway error"); }); if (body?.error) { let message = typeof body.error.message ? body.error.message : "Internal server error"; let code = typeof body.error?.code === "string" ? body.error.code : "CLIENT_GATEWAY_MISSING_CODE"; throw new ClientError(res.status, code, message); } return body; } json_headers({ ip, ua, token, wpayload }) { const headers = new Headers(); if (ip) headers.append(FORWARD_IP_HEADER, ip); // remove default user agent headers.append("user-agent", ua || "openstream-unknown"); if (token) headers.append(ACCESS_TOKEN_HEADER, token); if (wpayload) headers.append("content-type", "application/json"); return headers; } async json_request(url, init) { const res = await this.fetch(url, init); const body = await this.get_json_body(res); return body; } async get(ip, ua, token, url) { return await this.json_request(url, { headers: this.json_headers({ ip, ua, token, wpayload: false }), }); } async delete(ip, ua, token, url) { return await this.json_request(url, { method: "DELETE", headers: this.json_headers({ ip, ua, token, wpayload: false }), }); } async post(ip, ua, token, url, payload) { return await this.json_request(url, { method: "POST", headers: this.json_headers({ ip, ua, token, wpayload: true }), body: JSON.stringify(payload) }); } async put(ip, ua, token, url, payload) { return await this.json_request(url, { method: "PUT", headers: this.json_headers({ ip, ua, token, wpayload: true }), body: JSON.stringify(payload) }); } async patch(ip, ua, token, url, payload) { return await this.json_request(url, { method: "PATCH", headers: this.json_headers({ ip, ua, token, wpayload: true }), body: JSON.stringify(payload) }); } async get_stream_stats(ip, ua, token) { return await this.get(ip, ua, token, `/stream-stats`); } async get_stream_stats_item_now(ip, ua, token) { return await this.get(ip, ua, token, `/stream-stats/now`); } async get_stream_stats_item_now_count(ip, ua, token) { return await this.get(ip, ua, token, `/stream-stats/now/count`); } async get_stream_stats_now_count_by_station(ip, ua, token) { return await this.get(ip, ua, token, `/stream-stats/now/count-by-station`); } async get_stream_stats_item_since(ip, ua, token, num, unit) { return await this.get(ip, ua, token, `/stream-stats/last-${num}${unit}`); } async get_stream_stats_item_since_count(ip, ua, token, num, unit) { return await this.get(ip, ua, token, `/stream-stats/last-${num}${unit}/count`); } } export class Me { client; devices; api_keys; constructor(client) { this.client = client; this.devices = new MeDevices(client); this.api_keys = new MeApiKeys(client); } async me(ip, ua, token) { return await this.client.get(ip, ua, token, `/me`); } } export class MeDevices { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/me/devices${qss(query)}`); } async delete(ip, ua, token, id) { return await this.client.delete(ip, ua, token, `/me/devices/${id}`); } } export class MeApiKeys { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/me/api-keys${qss(query)}`); } async post(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/me/api-keys`, payload); } async patch(ip, ua, token, id, payload) { return await this.client.patch(ip, ua, token, `/me/api-keys/${id}`, payload); } async delete(ip, ua, token, id) { return await this.client.delete(ip, ua, token, `/me/api-keys/${id}`); } } export class Auth { client; user; admin; constructor(client) { this.client = client; this.user = new AuthUser(client); this.admin = new AuthAdmin(client); } async send_email_verification_code(ip, ua, payload) { return await this.client.post(ip, ua, null, `/auth/email-verification/send-code`, payload); } } export class AuthAdmin { client; constructor(client) { this.client = client; } async login(ip, ua, token, payload) { return await this.client.post(ip, ua, token, "/auth/admin/login", payload); } async logout(ip, ua, token) { return await this.client.post(ip, ua, token, "/auth/admin/logout", void 0); } async delegate(ip, ua, token, user_id, payload) { return await this.client.post(ip, ua, token, `/auth/admin/delegate/${user_id}`, payload); } } export class AuthUser { client; recovery_token; constructor(client) { this.client = client; this.recovery_token = new AuthUserRecoveryToken(this.client); } async email_exists(ip, ua, token, email) { return await this.client.get(ip, ua, token, `/auth/user/email-exists/${email}`); } async login(ip, ua, token, payload) { return await this.client.post(ip, ua, token, "/auth/user/login", payload); } async logout(ip, ua, token) { return await this.client.post(ip, ua, token, "/auth/user/logout", void 0); } async register(ip, ua, token, payload) { return await this.client.post(ip, ua, token, "/auth/user/register", payload); } async recover(ip, ua, token, payload) { return await this.client.post(ip, ua, token, "/auth/user/recover", payload); } } export class AuthUserRecoveryToken { client; constructor(client) { this.client = client; } async get(ip, ua, token, key) { return await this.client.get(ip, ua, token, `/auth/user/recovery-token/${key}`); } async set_password(ip, ua, token, key, payload) { return await this.client.post(ip, ua, token, `/auth/user/recovery-token/${key}/set-password`, payload); } } export class Plans { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/plans${qss(query)}`); } async get(ip, ua, token, plan_id) { return await this.client.get(ip, ua, token, `/plans/${plan_id}`); } async get_by_slug(ip, ua, token, plan_slug) { return await this.client.get(ip, ua, token, `/plans/by-slug/${plan_slug}`); } async post(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/plans`, payload); } async patch(ip, ua, token, plan_id, payload) { return await this.client.patch(ip, ua, token, `/plans/${plan_id}`, payload); } async delete(ip, ua, token, plan_id) { return await this.client.delete(ip, ua, token, `/plans/${plan_id}`); } } export class Accounts { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/accounts${qss(query)}`); } async get(ip, ua, token, id) { return await this.client.get(ip, ua, token, `/accounts/${id}`); } async post(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/accounts`, payload); } async patch(ip, ua, token, account_id, payload) { return await this.client.patch(ip, ua, token, `/accounts/${account_id}`, payload); } async delete(ip, ua, token, account_id) { return await this.client.delete(ip, ua, token, `/accounts/${account_id}`); } async list_members(ip, ua, token, account_id) { return await this.client.get(ip, ua, token, `/accounts/${account_id}/members`); } async delete_member(ip, ua, token, account_id, member_id) { return await this.client.delete(ip, ua, token, `/accounts/${account_id}/members/${member_id}`); } async set_member_role(ip, ua, token, account_id, member_id, payload) { return await this.client.post(ip, ua, token, `/accounts/${account_id}/members/${member_id}/set-role`, payload); } async get_stream_stats(ip, ua, token, account_id) { return await this.client.get(ip, ua, token, `/accounts/${account_id}/stream-stats`); } async get_stream_stats_item_now(ip, ua, token, account_id) { return await this.client.get(ip, ua, token, `/accounts/${account_id}/stream-stats/now`); } async get_stream_stats_item_now_count(ip, ua, token, account_id) { return await this.client.get(ip, ua, token, `/accounts/${account_id}/stream-stats/now/count`); } async get_stream_stats_now_count_by_station(ip, ua, token, account_id) { return await this.client.get(ip, ua, token, `/accounts/${account_id}/stream-stats/now/count-by-station`); } async get_stream_stats_item_since(ip, ua, token, account_id, num, unit) { return await this.client.get(ip, ua, token, `/accounts/${account_id}/stream-stats/last-${num}${unit}`); } async get_stream_stats_item_since_count(ip, ua, token, account_id, num, unit) { return await this.client.get(ip, ua, token, `/accounts/${account_id}/stream-stats/last-${num}${unit}/count`); } } export class Stations { client; files; pictures; constructor(client) { this.client = client; this.files = new StationFiles(client); this.pictures = new StationPictures(client); } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/stations${qss(query)}`); } async get(ip, ua, token, id) { return await this.client.get(ip, ua, token, `/stations/${id}`); } async delete(ip, ua, token, id) { return await this.client.delete(ip, ua, token, `/stations/${id}`); } async post(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/stations`, payload); } async is_slug_available(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/stations/is-slug-available${qss(query)}`); } async transfer(ip, ua, token, id, payload) { return await this.client.post(ip, ua, token, `/stations/${id}/transfer`, payload); } async patch(ip, ua, token, id, payload) { return await this.client.patch(ip, ua, token, `/stations/${id}`, payload); } async get_stream_stats(ip, ua, token, id) { return await this.client.get(ip, ua, token, `/stations/${id}/stream-stats`); } async get_stream_stats_item_now(ip, ua, token, id) { return await this.client.get(ip, ua, token, `/stations/${id}/stream-stats/now`); } async get_stream_stats_item_now_count(ip, ua, token, id) { return await this.client.get(ip, ua, token, `/stations/${id}/stream-stats/now/count`); } async get_stream_stats_item_since(ip, ua, token, id, num, unit) { return await this.client.get(ip, ua, token, `/stations/${id}/stream-stats/last-${num}${unit}`); } async get_stream_stats_item_since_count(ip, ua, token, id, num, unit) { return await this.client.get(ip, ua, token, `/stations/${id}/stream-stats/last-${num}${unit}/count`); } async get_now_playing(ip, ua, token, id) { return await this.client.get(ip, ua, token, `/stations/${id}/now-playing`); } // async get_dashboard_stats(ip: string | null, ua: string | null, token: string, id: string): Promise<import("./defs/api/stations/[station]/dashboard-stats/GET/Output.js").Output> { // return await this.client.get(ip, ua, token, `/stations/${id}/dashboard-stats`); // } async restart_playlist(ip, ua, token, id) { return await this.client.post(ip, ua, token, `/stations/${id}/restart-playlist`, undefined); } async reset_source_password(ip, ua, token, id) { return await this.client.post(ip, ua, token, `/stations/${id}/reset-source-password`, undefined); } } export class StationPictures { client; constructor(client) { this.client = client; } async post(ip, ua, token, query, data) { const headers = new Headers(); if (ip) headers.append(FORWARD_IP_HEADER, ip); if (ua) headers.append("user-agent", ua); headers.append(ACCESS_TOKEN_HEADER, token); headers.append("content-type", "application/octet-stream"); let res = await this.client.fetch(`/station-pictures${qss(query)}`, { method: "POST", headers, body: data }); return await this.client.get_json_body(res); } } export class Admins { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/admins${qss(query)}`); } async get(ip, ua, token, admin_id) { return await this.client.get(ip, ua, token, `/admins/${admin_id}`); } async post(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/admins`, payload); } async patch(ip, ua, token, admin_id, payload) { return await this.client.patch(ip, ua, token, `/admins/${admin_id}`, payload); } async change_password(ip, ua, token, admin_id, payload) { return await this.client.post(ip, ua, token, `/admins/${admin_id}/change-password`, payload); } } export class Users { client; stations; constructor(client) { this.client = client; this.stations = new UserStations(client); } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/users${qss(query)}`); } async get(ip, ua, token, user_id) { return await this.client.get(ip, ua, token, `/users/${user_id}`); } async post(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/users`, payload); } async patch(ip, ua, token, user_id, payload) { return await this.client.patch(ip, ua, token, `/users/${user_id}`, payload); } async delete(ip, ua, token, user_id) { return await this.client.delete(ip, ua, token, `/users/${user_id}`); } async change_password(ip, ua, token, user_id, payload) { return await this.client.post(ip, ua, token, `/users/${user_id}/change-password`, payload); } } export class UserStations { client; constructor(client) { this.client = client; } } export class StationFiles { client; constructor(client) { this.client = client; } async list(ip, ua, token, station_id, query) { return await this.client.get(ip, ua, token, `/stations/${station_id}/files${qss(query)}`); } async get(ip, ua, token, station_id, file_id) { return await this.client.get(ip, ua, token, `/stations/${station_id}/files/${file_id}`); } async delete(ip, ua, token, station_id, file_id) { return await this.client.delete(ip, ua, token, `/stations/${station_id}/files/${file_id}`); } async post(ip, ua, token, station_id, content_type, content_length, query, data) { const headers = new Headers(); if (ip) headers.append(FORWARD_IP_HEADER, ip); if (ua) headers.append("user-agent", ua); headers.append(ACCESS_TOKEN_HEADER, token); headers.append("content-type", content_type); headers.append("content-length", String(content_length)); let res = await this.client.fetch(`/stations/${station_id}/files${qss(query)}`, { method: "POST", headers, body: data }); return await this.client.get_json_body(res); } async put_metadata(ip, ua, token, station_id, file_id, payload) { return await this.client.put(ip, ua, token, `/stations/${station_id}/files/${file_id}/metadata`, payload); } async shuffle(ip, ua, token, station_id) { return await this.client.post(ip, ua, token, `/stations/${station_id}/files/shuffle`, undefined); } async unshuffle(ip, ua, token, station_id) { return await this.client.post(ip, ua, token, `/stations/${station_id}/files/unshuffle`, undefined); } async swap_order(ip, ua, token, station_id, file_id, payload) { return await this.client.post(ip, ua, token, `/stations/${station_id}/files/${file_id}/order/swap`, payload); } async move_to_first(ip, ua, token, station_id, file_id) { return await this.client.post(ip, ua, token, `/stations/${station_id}/files/${file_id}/order/move-to-first`, undefined); } async move_to_last(ip, ua, token, station_id, file_id) { return await this.client.post(ip, ua, token, `/stations/${station_id}/files/${file_id}/order/move-to-last`, undefined); } async move_before(ip, ua, token, station_id, file_id, payload) { return await this.client.post(ip, ua, token, `/stations/${station_id}/files/${file_id}/order/move-before`, payload); } async move_after(ip, ua, token, station_id, file_id, payload) { return await this.client.post(ip, ua, token, `/stations/${station_id}/files/${file_id}/order/move-after`, payload); } } export class Analytics { client; constructor(client) { this.client = client; } async get(ip, ua, token, query) { const url = `/analytics${qss(query)}`; return await this.client.get(ip, ua, token, url); } } export class AppAnalytics { client; constructor(client) { this.client = client; } async get(ip, ua, token, query) { const url = `/app-analytics${qss(query)}`; return await this.client.get(ip, ua, token, url); } } export class PaymentMethods { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/payment-methods${qss(query)}`); } async post(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/payment-methods`, payload); } async get(ip, ua, token, payment_method_id) { return await this.client.get(ip, ua, token, `/payment-methods/${payment_method_id}`); } } export class StreamConnections { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/stream-connections${qss(query)}`); } } export class StreamConnectionsLite { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/stream-connections-lite${qss(query)}`); } } export class AccountInvitations { client; constructor(client) { this.client = client; } async list(ip, ua, token, query) { return await this.client.get(ip, ua, token, `/invitations${qss(query)}`); } async post(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/invitations`, payload); } async get(ip, ua, token, invitation_id) { return await this.client.get(ip, ua, token, `/invitations/${invitation_id}`); } async delete(ip, ua, token, invitation_id) { return await this.client.delete(ip, ua, token, `/invitations/${invitation_id}`); } async get_by_token(ip, ua, token, invitation_token) { return await this.client.get(ip, ua, token, `/invitations/get-by-token/${invitation_token}`); } async accept(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/invitations/accept`, payload); } async reject(ip, ua, token, payload) { return await this.client.post(ip, ua, token, `/invitations/reject`, payload); } }