UNPKG

@melonly-moderation/api-client

Version:

Official TypeScript client for the Melonly API with full type safety and zero dependencies (basically)

4 lines 7.64 kB
/* Melonly API Client - Official TypeScript SDK */ var p=class r extends Error{constructor(t,s,n){super(s);this.status=t;this.details=n;this.name="MelonlyError";this.timestamp=new Date().toISOString();Object.setPrototypeOf(this,r.prototype);}toJSON(){return {name:this.name,message:this.message,status:this.status,details:this.details,timestamp:this.timestamp,stack:this.stack}}},m=class r extends Error{constructor(t,s){super(t);this.cause=s;this.name="NetworkError";this.timestamp=new Date().toISOString();Object.setPrototypeOf(this,r.prototype);}toJSON(){return {name:this.name,message:this.message,cause:this.cause?.message,timestamp:this.timestamp,stack:this.stack}}},l=class r extends p{constructor(t,s,n){super(429,t);this.retryAfterSeconds=s;this.resetTimestamp=n;this.name="RateLimitError";Object.setPrototypeOf(this,r.prototype);}get resetDate(){return this.resetTimestamp?new Date(this.resetTimestamp*1e3):void 0}get millisecondsUntilReset(){if(this.resetTimestamp)return Math.max(0,this.resetTimestamp*1e3-Date.now())}toJSON(){return {...super.toJSON(),retryAfterSeconds:this.retryAfterSeconds,resetTimestamp:this.resetTimestamp,resetDate:this.resetDate?.toISOString(),millisecondsUntilReset:this.millisecondsUntilReset}}},i=class r extends Error{constructor(t,s,n){super(t);this.field=s;this.value=n;this.name="ValidationError";this.timestamp=new Date().toISOString();Object.setPrototypeOf(this,r.prototype);}toJSON(){return {name:this.name,message:this.message,field:this.field,value:this.value,timestamp:this.timestamp,stack:this.stack}}};var g=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.token=e.token,this.timeout=e.timeout??3e4,this.maxRetries=e.maxRetries??3,this.debug=e.debug??false,this.defaultHeaders={Accept:"application/json","Content-Type":"application/json","User-Agent":"@melonly/api-client/1.0.0",...e.headers};}async get(e,t){let s=this.buildUrl(e,t);return this.request({method:"GET",url:s})}async post(e,t){let s=this.buildUrl(e);return this.request({method:"POST",url:s,body:t})}async put(e,t){let s=this.buildUrl(e);return this.request({method:"PUT",url:s,body:t})}async delete(e){let t=this.buildUrl(e);return this.request({method:"DELETE",url:t})}async patch(e,t){let s=this.buildUrl(e);return this.request({method:"PATCH",url:s,body:t})}buildUrl(e,t){let s=e.startsWith("/")?e:`/${e}`,n=`${this.baseUrl}${s}`;if(t&&Object.keys(t).length>0){let u=new URLSearchParams;Object.entries(t).forEach(([R,h])=>{h!=null&&u.append(R,String(h));});let c=u.toString();c&&(n+=`?${c}`);}return n}async request(e){let t;for(let s=1;s<=this.maxRetries;s++)try{return this.debug,await this.performRequest(e)}catch(n){if(t=n,n instanceof p&&n.status<500||n instanceof l)throw n;if(s===this.maxRetries)break;let u=Math.min(1e3*Math.pow(2,s-1),1e4)+Math.random()*1e3;this.debug,await this.sleep(u);}throw t??new m("Request failed after all retry attempts")}async performRequest(e){let t=new AbortController,s=setTimeout(()=>t.abort(),this.timeout);try{let n={...this.defaultHeaders,Authorization:`Bearer ${this.token}`,...e.headers},u={method:e.method,headers:n,signal:t.signal};e.body!==void 0&&(u.body=JSON.stringify(e.body));let c=await fetch(e.url,u);return clearTimeout(s),await this.handleResponse(c)}catch(n){throw clearTimeout(s),n instanceof Error&&n.name==="AbortError"?new m(`Request timeout after ${this.timeout}ms`):n instanceof TypeError&&n.message.includes("fetch")?new m("Network request failed - please check your connection"):n}}async handleResponse(e){let t=e.headers.get("content-type")??"",s;try{t.includes("application/json")?s=await e.json():s=await e.text();}catch(n){throw new p(e.status,"Failed to parse response body",{originalError:n})}if(!e.ok){if(e.status===429){let u=e.headers.get("retry-after"),c=e.headers.get("x-ratelimit-reset");throw new l("Rate limit exceeded",u?parseInt(u,10):void 0,c?parseInt(c,10):void 0)}let n=`HTTP ${e.status}: ${e.statusText}`;throw s&&typeof s=="object"&&"error"in s&&(n=String(s.error)),new p(e.status,n,s)}return s}sleep(e){return new Promise(t=>setTimeout(t,e))}};function f(r){if(!r)throw new i("API token is required","token",r);if(typeof r!="string")throw new i("API token must be a string","token",r);if(r.trim().length===0)throw new i("API token cannot be empty","token",r);if(r.length<10)throw new i("API token appears to be invalid (too short)","token",r)}function a(r,e){if(!r)throw new i(`${e} is required`,e,r);if(typeof r!="string")throw new i(`${e} must be a string`,e,r);if(r.trim().length===0)throw new i(`${e} cannot be empty`,e,r);if(r.includes("/")||r.includes("?")||r.includes("#"))throw new i(`${e} contains invalid characters`,e,r)}function o(r){if(r.page!==void 0){if(!Number.isInteger(r.page)||r.page<1)throw new i("Page must be a positive integer starting from 1","page",r.page);if(r.page>1e4)throw new i("Page number is too large (maximum: 10000)","page",r.page)}if(r.limit!==void 0){if(!Number.isInteger(r.limit)||r.limit<1)throw new i("Limit must be a positive integer","limit",r.limit);if(r.limit>100)throw new i("Limit cannot exceed 100 items per page","limit",r.limit)}}var d=class{constructor(e){f(e.token),this.http=new g({baseUrl:e.baseUrl??"https://api.melonly.xyz/api/v1",token:e.token,timeout:e.timeout??3e4,maxRetries:e.maxRetries??3,debug:e.debug??false,headers:e.headers});}async getApplications(e={}){return o(e),this.http.get("/server/applications",e)}async getApplication(e){return a(e,"applicationId"),this.http.get(`/server/applications/${encodeURIComponent(e)}`)}async getApplicationResponses(e,t={}){return a(e,"applicationId"),o(t),this.http.get(`/server/applications/${encodeURIComponent(e)}/responses`,t)}async getUserApplicationResponses(e,t={}){return a(e,"userId"),o(t),this.http.get(`/server/applications/user/${encodeURIComponent(e)}/responses`,t)}async getAuditLogs(e={}){return o(e),this.http.get("/server/audit-logs",e)}async getServerInfo(){return this.http.get("/server/info")}async getJoinRequests(e={}){return o(e),this.http.get("/server/join-requests",e)}async getJoinRequest(e){return a(e,"userId"),this.http.get(`/server/join-requests/${encodeURIComponent(e)}`)}async getLOAs(e={}){return o(e),this.http.get("/server/loas",e)}async getLOA(e){return a(e,"loaId"),this.http.get(`/server/loas/${encodeURIComponent(e)}`)}async getUserLOAs(e,t={}){return a(e,"memberId"),o(t),this.http.get(`/server/loas/user/${encodeURIComponent(e)}`,t)}async getLogs(e={}){return o(e),this.http.get("/server/logs",e)}async getLog(e){return a(e,"logId"),this.http.get(`/server/logs/${encodeURIComponent(e)}`)}async getStaffLogs(e,t={}){return a(e,"staffId"),o(t),this.http.get(`/server/logs/staff/${encodeURIComponent(e)}`,t)}async getUserLogs(e,t={}){if(!e?.trim())throw new Error("Username is required and cannot be empty");return o(t),this.http.get(`/server/logs/user/${encodeURIComponent(e)}`,t)}async getMembers(e={}){return o(e),this.http.get("/server/members",e)}async getMember(e){return a(e,"memberId"),this.http.get(`/server/members/${encodeURIComponent(e)}`)}async getMemberByDiscordId(e){return a(e,"discordId"),this.http.get(`/server/members/discord/${encodeURIComponent(e)}`)}async getRoles(e={}){return o(e),this.http.get("/server/roles",e)}async getRole(e){return a(e,"roleId"),this.http.get(`/server/roles/${encodeURIComponent(e)}`)}async getShifts(e={}){return o(e),this.http.get("/server/shifts",e)}async getShift(e){return a(e,"shiftId"),this.http.get(`/server/shifts/${encodeURIComponent(e)}`)}}; export{d as MelonlyClient,p as MelonlyError,m as NetworkError,l as RateLimitError,i as ValidationError};//# sourceMappingURL=index.mjs.map //# sourceMappingURL=index.mjs.map