UNPKG

@devnote-dev/pterojs

Version:

A verbose API library for Pterodactyl

1,759 lines (1,738 loc) 108 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Account: () => Account, ApplicationDatabaseManager: () => ApplicationDatabaseManager, ApplicationServer: () => ApplicationServer, ApplicationServerManager: () => ApplicationServerManager, BackupManager: () => BackupManager, BaseManager: () => BaseManager, BaseUser: () => BaseUser, Builder: () => Builder, ClientDatabaseManager: () => ClientDatabaseManager, ClientServer: () => ClientServer, ClientServerManager: () => ClientServerManager, Dict: () => Dict, FileManager: () => FileManager, Flags: () => Flags, NestEggsManager: () => NestEggsManager, NestManager: () => NestManager, NetworkManager: () => NetworkManager, Node: () => Node, NodeAllocationManager: () => NodeAllocationManager, NodeBuilder: () => NodeBuilder, NodeLocationManager: () => NodeLocationManager, NodeManager: () => NodeManager, Permissions: () => Permissions, PteroAPIError: () => PteroAPIError, PteroApp: () => PteroApp, PteroClient: () => PteroClient, RequestError: () => RequestError, RequestManager: () => RequestManager, Schedule: () => Schedule, ScheduleManager: () => ScheduleManager, ServerBuilder: () => ServerBuilder, ServerStatus: () => ServerStatus, Shard: () => Shard, ShardStatus: () => ShardStatus, SubUser: () => SubUser, SubUserManager: () => SubUserManager, User: () => User, UserBuilder: () => UserBuilder, UserManager: () => UserManager, ValidationError: () => ValidationError, WebSocketError: () => WebSocketError, WebSocketManager: () => WebSocketManager, buildQuery: () => buildQuery, caseConv: () => caseConv_default, configLoader: () => config_default, escape: () => escape_default, version: () => version2 }); module.exports = __toCommonJS(src_exports); // package.json var version = "2.2.2"; // src/structures/BaseManager.ts var BaseManager = class { constructor() { this.meta = { current: 0, total: 0, count: 0, perPage: 0, totalPages: 0 }; } getQueryOptions() { return { filters: this.FILTERS, sorts: this.SORTS, includes: this.INCLUDES }; } async getFetchAll(...options) { const opts = options[options.length - 1] || { page: 1 }; let data = await this.fetch(...options); if (this.meta.totalPages > 1) { for (let i = 2; i <= this.meta.totalPages; i++) { opts.page = i; let page = await this.fetch(opts); data.update(page); } } return data; } }; __name(BaseManager, "BaseManager"); // src/structures/Dict.ts var _Dict = class extends Map { constructor() { super(...arguments); this._limit = 0; } get limit() { return this._limit; } setLimit(amount) { if (this._limit) throw new Error("Cannot override a set limit."); this._limit = amount < 0 ? 0 : amount; } isLimited() { return !!this._limit && super.size === this._limit; } set(key, value) { if (this.isLimited()) throw new Error(`Dict has reached its limit (${this._limit})`); return super.set(key, value); } some(fn) { for (const [k, v] of this) if (fn(v, k, this)) return true; return false; } every(fn) { for (const [k, v] of this) if (!fn(v, k, this)) return false; return true; } hasAny(...keys) { return keys.some((k) => super.has(k)); } hasAll(...keys) { return keys.every((k) => super.has(k)); } first(amount) { const v = [...super.values()]; if (amount === void 0) return v[0]; const s = v.splice(0, amount); return s.length === 1 ? s[0] : s; } firstKey(amount) { const k = [...super.keys()]; if (amount === void 0) return k[0]; const s = k.splice(0, amount); return s.length === 1 ? s[0] : s; } last(amount) { const v = [...super.values()]; if (amount === void 0) return v[v.length - 1]; const s = v.slice(-amount); return s.length === 1 ? s[0] : s; } lastKey(amount) { const k = [...super.keys()]; if (amount === void 0) return k[k.length - 1]; const s = k.slice(-amount); return s.length === 1 ? s[0] : s; } random(amount) { const v = [...super.values()]; if (amount === void 0) return v[Math.floor(Math.random() * v.length)]; const s = []; for (let i = 0; i < amount; i++) s.push(v[Math.floor(Math.random() * v.length)]); return s.length === 1 ? s[0] : s; } randomKey(amount) { const k = [...super.keys()]; if (amount === void 0) return k[Math.floor(Math.random() * k.length)]; const s = []; for (let i = 0; i < amount; i++) s.push(k[Math.floor(Math.random() * k.length)]); return s.length === 1 ? s[0] : s; } map(fn) { const res = []; for (const [k, v] of this) res.push(fn(v, k, this)); return res; } filter(fn) { const res = new _Dict(); for (const [k, v] of this) if (fn(v, k, this)) res.set(k, v); return res; } find(fn) { for (const [k, v] of this) if (fn(v, k, this)) return v; return void 0; } sweep(fn) { let res = 0; for (const [k, v] of this) if (fn(v, k, this)) super.delete(k) && res++; return res; } part(fn) { const pass = new _Dict(); const fail = new _Dict(); for (const [k, v] of this) if (fn(v, k, this)) pass.set(k, v); else fail.set(k, v); return [pass, fail]; } reduce(fn, acc) { for (const [k, v] of this) acc = fn(v, k, this); return acc; } join(...dict) { const res = this.clone(); for (const d of dict) for (const [k, v] of d) res.set(k, v); return res; } difference(dict) { const res = new _Dict(); for (const [k, v] of this) if (!dict.has(k)) res.set(k, v); for (const [k, v] of dict) if (!super.has(k)) res.set(k, v); return res; } update(dict) { for (const [k, v] of dict) this.set(k, v); } clone() { return new _Dict(super.entries()); } }; var Dict = _Dict; __name(Dict, "Dict"); "constructor"; // src/structures/Errors.ts var PteroAPIError = class extends Error { constructor(data) { const fmt = data.errors.map((e) => `- ${e.status}: ${e.detail || "No details provided"}`).join("\n"); super("\n" + fmt); this.codes = data.errors.map((e) => e.code); this.meta = data.errors.map((e) => e.meta).filter(Boolean); } }; __name(PteroAPIError, "PteroAPIError"); var RequestError = class extends Error { }; __name(RequestError, "RequestError"); var ValidationError = class extends Error { constructor(...args) { switch (args.length) { case 3: super( `Failed to validate ${args[0]}: expected ${args[1]}; got ${args[2]}` ); break; case 2: break; case 1: super(`Validation: ${args[0]}`); break; default: super("Validation check failed."); break; } } }; __name(ValidationError, "ValidationError"); var WebSocketError = class extends Error { }; __name(WebSocketError, "WebSocketError"); // src/util/caseConv.ts function camelCase(str) { let res = ""; let next = false; str.split("").forEach((c) => { if (next) { next = false; res += c.toUpperCase(); } else if (c === "_") { next = true; } else { res += c; } }); return res; } __name(camelCase, "camelCase"); function toCamelCase(obj, options = {}) { if (typeof obj !== "object") return obj; const parsed = {}; if (Array.isArray(obj)) { return obj.map((i) => toCamelCase(i)); } for (let [k, v] of Object.entries(obj)) { if (options.ignore?.includes(k)) continue; if (options.map?.[k]) k = options.map[k]; if (options.cast?.[k]) { try { const cls = options.cast[k]; v = new cls(v); } catch { v = String(v); } } if (Array.isArray(v)) { v = v.map((i) => toCamelCase(i)); } else if (typeof v === "object" && !!v) { v = toCamelCase(v); } parsed[camelCase(k)] = v; } return parsed; } __name(toCamelCase, "toCamelCase"); function snakeCase(str) { let res = ""; const isUpper = /* @__PURE__ */ __name((c) => "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("").includes(c), "isUpper"); str.split("").forEach((c) => { if (isUpper(c)) res += "_"; res += c.toLowerCase(); }); return res; } __name(snakeCase, "snakeCase"); function toSnakeCase(obj, options = {}) { if (typeof obj !== "object") return obj; const parsed = {}; if (Array.isArray(obj)) { return obj.map((i) => toSnakeCase(i)); } for (let [k, v] of Object.entries(obj)) { if (options.ignore?.includes(k)) continue; if (options.map?.[k]) k = options.map[k]; if (options.cast?.[k]) { try { const cls = options.cast[k]; v = new cls(v); } catch { v = String(v); } } if (Array.isArray(v)) { v = v.map((i) => toSnakeCase(i)); } else if (typeof v === "object" && !!v) { v = toSnakeCase(v); } parsed[snakeCase(k)] = v; } return parsed; } __name(toSnakeCase, "toSnakeCase"); var caseConv_default = { toCamelCase, toSnakeCase }; // src/application/endpoints.ts var endpoints_default = { users: { main: "/users", get: (u) => `/users/${u}`, ext: (u) => `/users/external/${u}` }, nodes: { main: "/nodes", get: (n) => `/nodes/${n}`, deploy: "/nodes/deployable", config: (n) => `/nodes/${n}/configuration`, allocations: { main: (n) => `/nodes/${n}/allocations`, get: (n, a) => `/nodes/${n}/allocations/${a}` } }, servers: { main: "/servers", get: (s) => `/servers/${s}`, ext: (s) => `/servers/external/${s}`, details: (s) => `/servers/${s}/details`, build: (s) => `/servers/${s}/build`, startup: (s) => `/servers/${s}/startup`, suspend: (s) => `/servers/${s}/suspend`, unsuspend: (s) => `/servers/${s}/unsuspend`, reinstall: (s) => `/servers/${s}/reinstall`, databases: { main: (s) => `/servers/${s}/databases`, get: (s, id) => `/servers/${s}/databases/${id}`, reset: (s, id) => `/servers/${s}/databases/${id}/reset-password` } }, locations: { main: "/locations", get: (l) => `/locations/${l}` }, nests: { main: "/nests", get: (n) => `/nests/${n}`, eggs: { main: (n) => `/nests/${n}/eggs`, get: (n, e) => `/nests/${n}/eggs/${e}` } } }; // src/application/ApplicationDatabaseManager.ts var ApplicationDatabaseManager = class extends BaseManager { constructor(client, serverId) { super(); this.client = client; this.cache = new Dict(); this.serverId = serverId; } get FILTERS() { return Object.freeze([]); } get INCLUDES() { return Object.freeze(["host", "password"]); } get SORTS() { return Object.freeze([]); } _patch(data) { if (data.data) { const res = new Dict(); for (let o of data.data) { const d2 = caseConv_default.toCamelCase( o.attributes ); } this.cache.update(res); return res; } const d = caseConv_default.toCamelCase(data.attributes); this.cache.set(d.id, d); return d; } async fetch(op, ops = {}) { let path; switch (typeof op) { case "number": { if (!ops.force && this.cache.has(op)) return this.cache.get(op); path = endpoints_default.servers.databases.get(this.serverId, op); break; } case "undefined": case "object": { path = endpoints_default.servers.databases.main(this.serverId); if (op) ops = op; break; } default: throw new ValidationError( `expected database id or fetch options; got ${typeof op}` ); } const data = await this.client.requests.get(path, ops, null, this); return this._patch(data); } async create(database, remote, host) { if (!/^[0-9%.]{1,15}$/.test(remote)) throw new ValidationError( "remote did not pass the required validation: /^[0-9%.]{1,15}$/" ); const data = await this.client.requests.post( endpoints_default.servers.databases.main(this.serverId), { database, remote, host } ); return this._patch(data); } async resetPasword(id) { await this.client.requests.post( endpoints_default.servers.databases.reset(this.serverId, id) ); } async delete(id) { await this.client.requests.delete( endpoints_default.servers.databases.get(this.serverId, id) ); this.cache.delete(id); } }; __name(ApplicationDatabaseManager, "ApplicationDatabaseManager"); // src/structures/ApplicationServer.ts var ApplicationServer = class { constructor(client, data) { this.client = client; this.databases = new ApplicationDatabaseManager(client, data.id); this.id = data.id; this.uuid = data.uuid; this.identifier = data.identifier; this.createdAt = new Date(data.created_at); this.createdTimestamp = this.createdAt.getTime(); this._patch(data); } _patch(data) { if ("external_id" in data) this.externalId = data.external_id; if ("name" in data) this.name = data.name; if ("description" in data) this.description = data.description || void 0; if ("status" in data) this.status = data.status; if ("suspended" in data) this.suspended = data.suspended; if ("limits" in data) this.limits = caseConv_default.toCamelCase(data.limits); if ("feature_limits" in data) this.featureLimits = data.feature_limits; if ("user" in data) this.ownerId = data.user; if ("node" in data) this.nodeId = data.node; if ("allocation" in data) this.allocation = data.allocation; if ("nest" in data) this.nest = data.nest; if ("egg" in data) this.egg = data.egg; if ("container" in data) { this.container = caseConv_default.toCamelCase(data.container, { ignore: ["environment"] }); this.container.environment = data.container.environment; this.container.installed = !!this.container.installed; } if ("relationships" in data) { this.owner = "user" in data.relationships ? this.client.users.resolve(data) : void 0; this.node = "node" in data.relationships ? this.client.nodes.resolve(data) : void 0; } } get panelURL() { return `${this.client.domain}/server/${this.identifier}`; } get adminURL() { return `${this.client.domain}/admin/servers/view/${this.id}`; } async fetchOwner() { if (this.owner) return this.owner; const user = await this.client.users.fetch(this.ownerId, { force: true }); this.owner = user; return user; } async updateDetails(options) { const data = await this.client.servers.updateDetails(this.id, options); this._patch(data.toJSON()); return this; } async updateBuild(options) { const data = await this.client.servers.updateBuild(this.id, options); this._patch(data); return this; } async updateStartup(options) { const data = await this.client.servers.updateStartup(this.id, options); this._patch(data); return this; } async suspend() { await this.client.servers.suspend(this.id); } async unsuspend() { await this.client.servers.unsuspend(this.id); } async reinstall() { await this.client.servers.reinstall(this.id); } toJSON() { return caseConv_default.toSnakeCase(this, { ignore: ["client", "user", "node"], map: { ownerId: "user", nodeId: "node" } }); } toString() { return this.name; } }; __name(ApplicationServer, "ApplicationServer"); // src/application/ApplicationServerManager.ts var ApplicationServerManager = class extends BaseManager { constructor(client) { super(); this.client = client; this.cache = new Dict(); this.meta = { current: 0, total: 0, count: 0, perPage: 0, totalPages: 0 }; } get FILTERS() { return Object.freeze([ "name", "uuid", "uuidShort", "externalId", "image" ]); } get INCLUDES() { return Object.freeze([ "allocations", "user", "subusers", "nest", "egg", "variables", "location", "node", "databases" ]); } get SORTS() { return Object.freeze(["id", "-id", "uuid", "-uuid"]); } get defaultLimits() { return { memory: 128, swap: 0, disk: 512, io: 500, cpu: 100, threads: null }; } get defaultFeatureLimits() { return { allocations: 1, databases: 1, backups: 1 }; } _patch(data) { if (data?.meta?.pagination) { this.meta = caseConv_default.toCamelCase(data.meta.pagination, { ignore: ["current_page"] }); this.meta.current = data.meta.pagination.current_page; } if (data.data) { const res = new Dict(); for (let o of data.data) { const s2 = new ApplicationServer(this.client, o.attributes); res.set(s2.id, s2); } if (this.client.options.servers.cache) this.cache.update(res); return res; } const s = new ApplicationServer(this.client, data.attributes); if (this.client.options.servers.cache) this.cache.set(s.id, s); return s; } resolve(obj) { if (obj instanceof ApplicationServer) return obj; if (typeof obj === "number") return this.cache.get(obj); if (typeof obj === "string") return this.cache.find((s) => s.name === obj); if (obj.relationships?.servers) return this._patch(obj.relationships.servers); return void 0; } adminURLFor(id) { return `${this.client.domain}/admin/servers/view/${id}`; } panelURLFor(id) { return `${this.client.domain}/server/${id}`; } async fetch(op, ops = {}) { let path; switch (typeof op) { case "number": { if (!ops.force && this.cache.has(op)) return this.cache.get(op); path = endpoints_default.servers.get(op); break; } case "string": { if (!ops.force) { const u = this.cache.find((u2) => u2.externalId === op); if (u) return u; } path = endpoints_default.servers.ext(op); break; } case "undefined": case "object": { path = endpoints_default.servers.main; if (op) ops = op; break; } default: throw new ValidationError( `expected server id, external id or fetch options; got ${typeof op}` ); } const data = await this.client.requests.get(path, ops, null, this); return this._patch(data); } fetchAll(options) { return this.getFetchAll(options); } async query(entity, options) { if (!options.sort && !options.filter) throw new ValidationError("Sort or filter is required."); if (options.filter === "identifier") options.filter = "uuidShort"; if (options.filter === "externalId") options.filter = "external_id"; const payload = {}; if (options.filter) payload.filter = [options.filter, entity]; if (options.sort) payload.sort = options.sort; const data = await this.client.requests.get( endpoints_default.servers.main, payload, null, this ); return this._patch(data); } async create(options) { options.limits = Object.assign( this.defaultLimits, options.limits || {} ); options.featureLimits = Object.assign( this.defaultFeatureLimits, options.featureLimits || {} ); const payload = caseConv_default.toSnakeCase(options, { ignore: ["environment"] }); payload.environment = options.environment; const data = await this.client.requests.post( endpoints_default.servers.main, payload ); return this._patch(data); } async updateDetails(id, options) { if (!Object.keys(options).length) throw new ValidationError("Too few options to update the server."); const server = await this.fetch(id, { force: true }); options.name ||= server.name; options.owner ??= server.ownerId; options.externalId ||= server.externalId; options.description ||= server.description; const payload = caseConv_default.toSnakeCase(options, { map: { owner: "user" } }); const data = await this.client.requests.patch( endpoints_default.servers.details(id), payload ); return this._patch(data); } async updateBuild(id, options) { if (!Object.keys(options).length) throw new ValidationError("Too few options to update the server."); const server = await this.fetch(id, { force: true }); options.limits = Object.assign(server.limits, options.limits); options.featureLimits = Object.assign( server.featureLimits, options.featureLimits ); options.allocation ??= server.allocation; const data = await this.client.requests.patch( endpoints_default.servers.build(id), caseConv_default.toSnakeCase(options) ); return this._patch(data); } async updateStartup(id, options) { if (!Object.keys(options).length) throw new ValidationError("Too few options to update the server."); const server = await this.fetch(id, { force: true }); options.egg ??= server.egg; options.environment ||= server.container.environment; options.image ||= server.container.image; options.skipScripts ??= false; options.startup ||= server.container.startupCommand; const payload = caseConv_default.toSnakeCase(options, { ignore: ["environment"] }); payload.environment = options.environment; const data = await this.client.requests.patch( endpoints_default.servers.startup(id), payload ); return this._patch(data); } suspend(id) { return this.client.requests.post(endpoints_default.servers.suspend(id)); } unsuspend(id) { return this.client.requests.post(endpoints_default.servers.unsuspend(id)); } reinstall(id) { return this.client.requests.post(endpoints_default.servers.reinstall(id)); } async delete(id, force = false) { await this.client.requests.delete( endpoints_default.servers.get(id) + (force ? "/force" : "") ); this.cache.delete(id); } }; __name(ApplicationServerManager, "ApplicationServerManager"); // src/application/NestEggsManager.ts var NestEggsManager = class extends BaseManager { constructor(client) { super(); this.client = client; this.cache = new Dict(); } get FILTERS() { return Object.freeze([]); } get INCLUDES() { return Object.freeze([ "nest", "servers", "config", "script", "variables" ]); } get SORTS() { return Object.freeze([]); } _patch(data) { if (data?.data) { const res = new Dict(); for (let o of data.data) { let e2 = caseConv_default.toCamelCase(o.attributes); e2.createdAt = new Date(e2.createdAt); e2.updatedAt &&= new Date(e2.updatedAt); res.set(e2.id, e2); } this.cache.update(res); return res; } let e = caseConv_default.toCamelCase(data.attributes); e.createdAt = new Date(e.createdAt); e.updatedAt &&= new Date(e.updatedAt); this.cache.set(e.id, e); return e; } adminURLFor(id) { return `${this.client.domain}/admin/nests/egg/${id}`; } async fetch(nest, op1, op2 = {}) { let path = endpoints_default.nests.eggs.main(nest); if (typeof op1 === "number") { if (!op2.force && this.cache.has(op1)) return this.cache.get(op1); path = endpoints_default.nests.eggs.get(nest, op1); } else { if (op1) op2 = op1; } const data = await this.client.requests.get(path, op2, null, this); return this._patch(data); } }; __name(NestEggsManager, "NestEggsManager"); // src/application/NestManager.ts var NestManager = class extends BaseManager { constructor(client) { super(); this.client = client; this.cache = new Dict(); this.eggs = new NestEggsManager(client); this.meta = { current: 0, total: 0, count: 0, perPage: 0, totalPages: 0 }; } get FILTERS() { return Object.freeze([]); } get INCLUDES() { return Object.freeze(["eggs", "servers"]); } get SORTS() { return Object.freeze([]); } _patch(data) { if (data?.meta?.pagination) { this.meta = caseConv_default.toCamelCase(data.meta.pagination, { ignore: ["current_page"] }); this.meta.current = data.meta.pagination.current_page; } if (data?.data) { const res = new Dict(); for (let o of data.data) { const n2 = caseConv_default.toCamelCase(o.attributes); n2.createdAt = new Date(n2.createdAt); n2.updatedAt &&= new Date(n2.updatedAt); res.set(n2.id, n2); } if (this.client.options.nests.cache) this.cache.update(res); return res; } const n = caseConv_default.toCamelCase(data.attributes); n.createdAt = new Date(n.createdAt); n.updatedAt &&= new Date(n.updatedAt); if (this.client.options.nodes.cache) this.cache.set(n.id, n); return n; } adminURLFor(id) { return `${this.client.domain}/admin/nests/view/${id}`; } async fetch(op, include = []) { let path = endpoints_default.nests.main; if (typeof op === "number") { path = endpoints_default.nests.get(op); } else { include.push(...op || []); } const data = await this.client.requests.get( path, { include }, null, this ); return this._patch(data); } }; __name(NestManager, "NestManager"); // src/application/NodeAllocationManager.ts var NodeAllocationManager = class extends BaseManager { constructor(client) { super(); this.client = client; this.cache = new Dict(); this.meta = { current: 0, total: 0, count: 0, perPage: 0, totalPages: 0 }; } get FILTERS() { return Object.freeze([]); } get INCLUDES() { return Object.freeze(["node", "server"]); } get SORTS() { return Object.freeze([]); } _patch(node, data) { if (data?.meta?.pagination) { this.meta = caseConv_default.toCamelCase(data.meta.pagination, { ignore: ["current_page"] }); this.meta.current = data.meta.pagination.current_page; } const res = new Dict(); for (let o of data.data) { const a = caseConv_default.toCamelCase(o.attributes); res.set(a.id, a); } const all = (this.cache.get(node) || new Dict()).join(res); this.cache.set(node, all); return res; } adminURLFor(id) { return `${this.client.domain}/admin/nodes/view/${id}/allocation`; } async fetch(node, options = {}) { if (!options.force) { const a = this.cache.get(node); if (a) return Promise.resolve(a); } const data = await this.client.requests.get( endpoints_default.nodes.allocations.main(node), options, null, this ); return this._patch(node, data); } fetchAll(node, options) { return this.getFetchAll(node, options); } async fetchAvailable(node, single) { const all = await this.fetchAll(node, { force: true }); return single ? all.filter((a) => !a.assigned).first() : all.filter((a) => !a.assigned); } async create(node, ip, ports) { if (!ports.every((p) => typeof p === "string")) throw new TypeError( "Allocation ports must be a string integer or string range." ); for (const port of ports) { if (!port.includes("-")) continue; const [_start, _stop] = port.split("-"); const start = Number(_start), stop = Number(_stop); if (start > stop) throw new RangeError("Start cannot be greater than stop."); if (start <= 1024 || stop > 65535) throw new RangeError( "Port range must be between 1024 and 65535." ); if (stop - start > 1e3) throw new RangeError("Maximum port range exceeded (1000)."); } await this.client.requests.post( endpoints_default.nodes.allocations.main(node), { ip, ports } ); } async delete(node, id) { await this.client.requests.delete( endpoints_default.nodes.allocations.get(node, id) ); this.cache.get(node)?.delete(id); } }; __name(NodeAllocationManager, "NodeAllocationManager"); // src/application/NodeLocationManager.ts var NodeLocationManager = class extends BaseManager { constructor(client) { super(); this.client = client; this.cache = new Dict(); this.meta = { current: 0, total: 0, count: 0, perPage: 0, totalPages: 0 }; } get FILTERS() { return Object.freeze(["short", "long"]); } get INCLUDES() { return Object.freeze(["nodes", "servers"]); } get SORTS() { return Object.freeze([]); } _patch(data) { if (data?.meta?.pagination) { this.meta = caseConv_default.toCamelCase(data.meta.pagination, { ignore: ["current_page"] }); this.meta.current = data.meta.pagination.current_page; } if (data?.data) { const res = new Dict(); for (let o of data.data) { const n = caseConv_default.toCamelCase(o.attributes); n.createdAt = new Date(n.createdAt); n.updatedAt &&= new Date(n.updatedAt); res.set(n.id, n); } if (this.client.options.locations.cache) this.cache.update(res); return res; } const loc = caseConv_default.toCamelCase(data.attributes); loc.createdAt = new Date(loc.createdAt); loc.updatedAt &&= new Date(loc.updatedAt); if (this.client.options.locations.cache) this.cache.set(data.id, loc); return loc; } resolve(obj) { if (typeof obj === "number") return this.cache.get(obj); if (typeof obj === "string") return this.cache.find((o) => o.short === obj || o.long === obj); if (obj.relationships?.location?.attributes) return this._patch(obj.relationships.location); return void 0; } adminURLFor(id) { return `${this.client.domain}/admin/locations/view/${id}`; } async fetch(op, ops = {}) { let path = endpoints_default.locations.main; if (typeof op === "number") { if (!ops.force && this.cache.has(op)) return this.cache.get(op); path = endpoints_default.locations.get(op); } else { if (op) ops = op; } const data = await this.client.requests.get(path, ops, null, this); return this._patch(data); } fetchAll(options) { return this.getFetchAll(options); } async query(entity, options) { if (!options.sort && !options.filter) throw new ValidationError("Sort or filter is required."); const payload = {}; if (options.filter) payload.filter = [options.filter, entity]; if (options.sort) payload.sort = options.sort; const data = await this.client.requests.get( endpoints_default.locations.main, payload, null, this ); return this._patch(data); } async create(short, long) { const data = await this.client.requests.post(endpoints_default.locations.main, { short, long }); return this._patch(data); } async update(id, options) { if (!options.short && !options.long) throw new ValidationError( "Either short or long is required to update the location" ); const data = await this.client.requests.patch( endpoints_default.locations.get(id), options ); return this._patch(data); } async delete(id) { await this.client.requests.delete(endpoints_default.locations.get(id)); this.cache.delete(id); } }; __name(NodeLocationManager, "NodeLocationManager"); // src/structures/Node.ts var Node = class { constructor(client, data) { this.client = client; this.id = data.id; this.uuid = data.uuid; this.createdAt = new Date(data.created_at); this._patch(data); } _patch(data) { if ("public" in data) this.public = data.public; if ("name" in data) this.name = data.name; if ("description" in data) this.description = data.description || void 0; if ("location_id" in data) this.locationId = data.location_id; if ("fqdn" in data) this.fqdn = data.fqdn; if ("scheme" in data) this.scheme = data.scheme; if ("behind_proxy" in data) this.behindProxy = data.behind_proxy; if ("maintenance_mode" in data) this.maintenance = data.maintenance_mode; if ("memory" in data) this.memory = data.memory; if ("memory_overallocate" in data) this.overallocatedMemory = data.memory_overallocate; if ("disk" in data) this.disk = data.disk; if ("disk_overallocate" in data) this.overallocatedDisk = data.disk_overallocate; if ("upload_size" in data) this.uploadSize = data.upload_size; if (!this.daemon) this.daemon = {}; if ("daemon_listen" in data) this.daemon.listening = data.daemon_listen; if ("daemon_sftp" in data) this.daemon.sftp = data.daemon_sftp; if ("daemon_base" in data) this.daemon.base = data.daemon_base; } get adminURL() { return `${this.client.domain}/admin/nodes/view/${this.id}`; } async getConfig() { return await this.client.nodes.getConfig(this.id); } async update(options) { const data = await this.client.nodes.update(this.id, options); this._patch(data.toJSON()); return this; } toJSON() { return caseConv_default.toSnakeCase(this, { ignore: ["client", "location", "servers"], map: { maintainance: "maintenance_mode", overallocatedMemory: "memory_overallocate", overallocatedDisk: "disk_overallocate" } }); } toString() { return this.name; } }; __name(Node, "Node"); // src/application/NodeManager.ts var NodeManager = class extends BaseManager { constructor(client) { super(); this.client = client; this.cache = new Dict(); this.meta = { current: 0, total: 0, count: 0, perPage: 0, totalPages: 0 }; } get FILTERS() { return Object.freeze(["uuid", "name", "fqdn", "daemon_token_id"]); } get INCLUDES() { return Object.freeze(["allocations", "location", "servers"]); } get SORTS() { return Object.freeze(["id", "uuid", "memory", "disk"]); } _patch(data) { if (data?.meta?.pagination) { this.meta = caseConv_default.toCamelCase(data.meta.pagination, { ignore: ["current_page"] }); this.meta.current = data.meta.pagination.current_page; } if (data?.data) { const res = new Dict(); for (const obj of data.data) { const s = new Node(this.client, obj.attributes); res.set(s.id, s); } if (this.client.options.servers.cache) this.cache.update(res); return res; } const n = new Node(this.client, data.attributes); if (this.client.options.nodes.cache) this.cache.set(n.id, n); return n; } resolve(obj) { if (obj instanceof Node) return obj; if (typeof obj === "number") return this.cache.get(obj); if (typeof obj === "string") return this.cache.find((n) => n.name === obj); if (obj.relationships?.node) return this._patch(obj.relationships.node); return void 0; } adminURLFor(id) { return `${this.client.domain}/admin/nodes/view/${id}`; } async fetch(op, ops = {}) { let path = endpoints_default.nodes.main; if (typeof op === "number") { if (!ops.force && this.cache.has(op)) return this.cache.get(op); path = endpoints_default.nodes.get(op); } else { if (op) ops = op; } const data = await this.client.requests.get(path, ops, null, this); return this._patch(data); } fetchAll(options) { return this.getFetchAll(options); } async fetchDeployable(options) { const data = await this.client.requests.get( endpoints_default.nodes.deploy, void 0, options ); return this._patch(data); } async query(entity, options) { if (!options.sort && !options.filter) throw new ValidationError("Sort or filter is required."); if (options.filter === "daemonTokenId") options.filter = "daemon_token_id"; const payload = {}; if (options.filter) payload.filter = [options.filter, entity]; if (options.sort) payload.sort = options.sort; const data = await this.client.requests.get( endpoints_default.nodes.main, payload, null, this ); return this._patch(data); } async getConfig(id) { const data = await this.client.requests.get(endpoints_default.nodes.config(id)); return caseConv_default.toCamelCase(data); } async create(options) { const payload = caseConv_default.toSnakeCase(options); const data = await this.client.requests.post( endpoints_default.nodes.main, payload ); return this._patch(data); } async update(id, options) { if (!Object.keys(options).length) throw new ValidationError("Too few options to update the node."); const _node = await this.fetch(id); options = Object.assign(options, _node); const payload = caseConv_default.toSnakeCase(options); const data = await this.client.requests.patch( endpoints_default.nodes.get(id), payload ); return this._patch(data); } async delete(id) { await this.client.requests.delete(endpoints_default.nodes.get(id)); this.cache.delete(id); } }; __name(NodeManager, "NodeManager"); // src/http/RequestManager.ts var import_axios = __toESM(require("axios")); var import_events = require("events"); // src/util/query.ts var buildQuery = /* @__PURE__ */ __name((args, allowed) => { const parsed = []; if (args.page) parsed.push(`page=${args.page}`); if (args.perPage && args.perPage > 0) { if (args.perPage > 100) args.perPage = 100; parsed.push(`per_page=${args.perPage}`); } if (args.filter) { if (!allowed.filters?.includes(args.filter[0])) throw new ValidationError( `Invalid filter argument '${args.filter[0]}'.` ); parsed.push(`filter[${args.filter[0]}]=${args.filter[1]}`); } if (args.include) { for (const arg of args.include) { if (!allowed.includes.includes(arg)) throw new ValidationError(`Invalid include argument '${arg}'.`); } if (args.include?.length) parsed.push(`include=${args.include}`); } if (args.sort) { if (!allowed.sorts.includes(args.sort)) throw new ValidationError(`Invalid sort argument '${args.sort}'.`); parsed.push(`sort=${args.sort}`); } if (!parsed.length) return ""; return "?" + parsed.join("&"); }, "buildQuery"); // src/http/RequestManager.ts var RequestManager = class extends import_events.EventEmitter { constructor(_type, _domain, _auth) { super(); this._type = _type; this._domain = _domain; this._auth = _auth; this.instance = import_axios.default.create({ baseURL: `${this._domain}/api/${this._type.toLowerCase()}` }); this._ping = -1; this._start = 0; } emit(event, ...args) { return super.emit(event, ...args); } on(event, listener) { super.on(event, listener); return this; } once(event, listener) { super.once(event, listener); return this; } off(event, listener) { super.off(event, listener); return this; } getHeaders() { return { "User-Agent": `PteroJS ${this._type} v${version}`, "Content-Type": "application/json", Accept: "application/json, text/plain", Authorization: `Bearer ${this._auth}` }; } debug(...data) { data.map((d) => `[HTTP] ${d}`).forEach((d) => super.emit("debug", d)); } async _make(method, path, body) { const headers = this.getHeaders(); if (body !== null && body !== void 0) { if (typeof body === "string") { headers["Content-Type"] = "text/plain"; } else { body = JSON.stringify(body); } super.emit("preRequest", body); } this.debug( `requesting: ${method} ${path}`, `payload: ${body ? headers["Content-Type"] : "none"}` ); this._start = Date.now(); return await this.instance.request({ method, url: path, headers, data: body }).then((r) => this.handleResponse(r)).catch((e) => this.handleError(e)); } async raw(method, url, body) { const headers = this.getHeaders(); if (body !== null && body !== void 0) { if (typeof body === "string") { headers["Content-Type"] = "text/plain"; } else { body = JSON.stringify(body); } super.emit("preRequest", body); } this.debug( `requesting: ${method} ${url}`, `payload: ${body ? headers["Content-Type"] : "none"}` ); this._start = Date.now(); return await import_axios.default.request({ url, method, headers, data: body }).then((r) => this.handleResponse(r)).catch((e) => this.handleError(e)); } handleResponse(res) { this._ping = Date.now() - this._start; this.debug( `received status: ${res.status} (${this._ping}ms)`, `body: ${res.data ? res.headers["content-type"] : "none"}` ); if ([202, 204].includes(res.status)) return; super.emit("postRequest", res.data); if (res.data.object && res.data.object === "null_resource") throw new RequestError("Request returned a null resource object"); return res.data; } handleError(err) { this._ping = Date.now() - this._start; this.debug( `received error: ${err.name} (${this._ping}ms)`, `message: ${err.message}` ); if (err.response === void 0) throw new RequestError( `An unknown request error occurred: ${err.message}` ); if (err.response.status >= 500) throw new RequestError( `Received an unexpected response from the API (code ${err.response.status})` ); throw new PteroAPIError(err.response.data); } get(path, params, body, cls) { const query = params && cls ? buildQuery(params, cls.getQueryOptions()) : ""; return this._make("GET", path + query, body); } post(path, body) { return this._make("POST", path, body); } patch(path, body) { return this._make("PATCH", path, body); } put(path, body) { return this._make("PUT", path, body); } delete(path, body) { return this._make("DELETE", path, body); } }; __name(RequestManager, "RequestManager"); // src/structures/Permissions.ts var Flags = /* @__PURE__ */ ((Flags2) => { Flags2["WEBSOCKET_CONNECT"] = "websocket.connect"; Flags2["CONTROL_CONSOLE"] = "control.console"; Flags2["CONTROL_START"] = "control.start"; Flags2["CONTROL_STOP"] = "control.stop"; Flags2["CONTROL_RESTART"] = "control.restart"; Flags2["USER_CREATE"] = "user.create"; Flags2["USER_READ"] = "user.read"; Flags2["USER_UPDATE"] = "user.update"; Flags2["USER_DELETE"] = "user.delete"; Flags2["FILE_CREATE"] = "file.create"; Flags2["FILE_READ"] = "file.read"; Flags2["FILE_READ_CONTENT"] = "file.read-content"; Flags2["FILE_UPDATE"] = "file.update"; Flags2["FILE_DELETE"] = "file.delete"; Flags2["FILE_ARCHIVE"] = "file.archive"; Flags2["FILE_SFTP"] = "file.sftp"; Flags2["BACKUP_CREATE"] = "backup.create"; Flags2["BACKUP_READ"] = "backup.read"; Flags2["BACKUP_UPDATE"] = "backup.update"; Flags2["BACKUP_DELETE"] = "backup.delete"; Flags2["ALLOCATION_READ"] = "allocation.read"; Flags2["ALLOCATION_CREATE"] = "allocation.create"; Flags2["ALLOCATION_UPDATE"] = "allocation.update"; Flags2["ALLOCATION_DELETE"] = "allocation.delete"; Flags2["STARTUP_READ"] = "startup.read"; Flags2["STARTUP_UPDATE"] = "startup.update"; Flags2["DATABASE_CREATE"] = "database.create"; Flags2["DATABASE_READ"] = "database.read"; Flags2["DATABASE_UPDATE"] = "database.update"; Flags2["DATABASE_DELETE"] = "database.delete"; Flags2["DATABASE_VIEW_PASSWORD"] = "database.view_password"; Flags2["SCHEDULE_CREATE"] = "schedule.create"; Flags2["SCHEDULE_READ"] = "schedule.read"; Flags2["SCHEDULE_UPDATE"] = "schedule.update"; Flags2["SCHEDULE_DELETE"] = "schedule.delete"; Flags2["SETTINGS_RENAME"] = "settings.rename"; Flags2["SETTINGS_REINSTALL"] = "settings.reinstall"; Flags2["ADMIN_WEBSOCKET_ERRORS"] = "admin.websocket.errors"; Flags2["ADMIN_WEBSOCKET_INSTALL"] = "admin.websocket.install"; Flags2["ADMIN_WEBSOCKET_TRANSFER"] = "admin.websocket.transfer"; return Flags2; })(Flags || {}); var Permissions = class { static get CONTROL() { return Object.freeze([ "control.console" /* CONTROL_CONSOLE */, "control.start" /* CONTROL_START */, "control.stop" /* CONTROL_STOP */, "control.restart" /* CONTROL_RESTART */ ]); } static get USERS() { return Object.freeze([ "user.create" /* USER_CREATE */, "user.read" /* USER_READ */, "user.update" /* USER_UPDATE */, "user.delete" /* USER_DELETE */ ]); } static get FILES() { return Object.freeze([ "file.create" /* FILE_CREATE */, "file.read" /* FILE_READ */, "file.read-content" /* FILE_READ_CONTENT */, "file.update" /* FILE_UPDATE */, "file.delete" /* FILE_DELETE */, "file.archive" /* FILE_ARCHIVE */, "file.sftp" /* FILE_SFTP */ ]); } static get BACKUPS() { return Object.freeze([ "backup.create" /* BACKUP_CREATE */, "backup.read" /* BACKUP_READ */, "backup.update" /* BACKUP_UPDATE */, "backup.delete" /* BACKUP_DELETE */ ]); } static get ALLOCATIONS() { return Object.freeze([ "allocation.read" /* ALLOCATION_READ */, "allocation.create" /* ALLOCATION_CREATE */, "allocation.update" /* ALLOCATION_UPDATE */, "allocation.delete" /* ALLOCATION_DELETE */ ]); } static get STARTUPS() { return Object.freeze(["startup.read" /* STARTUP_READ */, "startup.update" /* STARTUP_UPDATE */]); } static get DATABASES() { return Object.freeze([ "database.create" /* DATABASE_CREATE */, "database.read" /* DATABASE_READ */, "database.update" /* DATABASE_UPDATE */, "database.delete" /* DATABASE_DELETE */, "database.view_password" /* DATABASE_VIEW_PASSWORD */ ]); } static get SCHEDULES() { return Object.freeze([ "schedule.create" /* SCHEDULE_CREATE */, "schedule.read" /* SCHEDULE_READ */, "schedule.update" /* SCHEDULE_UPDATE */, "schedule.delete" /* SCHEDULE_DELETE */ ]); } static get SETTINGS() { return Object.freeze(["settings.rename" /* SETTINGS_RENAME */, "settings.reinstall" /* SETTINGS_REINSTALL */]); } static get ADMIN() { return Object.freeze([ "admin.websocket.errors" /* ADMIN_WEBSOCKET_ERRORS */, "admin.websocket.install" /* ADMIN_WEBSOCKET_INSTALL */, "admin.websocket.transfer" /* ADMIN_WEBSOCKET_TRANSFER */ ]); } constructor(...perms) { this.value = Permissions.resolve(...perms); } static resolve(...perms) { const res = []; const values = Object.values(Flags); if (perms.some((p) => p === "*")) return values; for (const p of perms) { if (p in Flags || values.includes(p)) { res.push(p); } else { throw new Error(`unknown permission '${p}'`); } } return res; } hasAny(...perms) { const res = Permissions.resolve(...perms); return res.some((p) => this.value.includes(p)); } hasAll(...perms) { const res = Permissions.resolve(...perms); return res.every((p) => this.value.includes(p)); } isAdmin() { return this.value.some( (p) => [ "admin.websocket.errors" /* ADMIN_WEBSOCKET_ERRORS */, "admin.websocket.install" /* ADMIN_WEBSOCKET_INSTALL */, "admin.websocket.transfer" /* ADMIN_WEBSOCKET_TRANSFER */ ].includes(p) ); } add(...perms) { this.value = this.value.concat(Permissions.resolve(...perms)); return this; } remove(...perms) { const res = Permissions.resolve(...perms); this.value = this.value.filter((p) => !res.includes(p)); return this; } serialize() { const res = {}; for (let [k, v] of Object.entries(Flags)) res[k] = this.value.includes(v); return res; } }; __name(Permissions, "Permissions"); // sr