serchat.ts 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -90,7 +90,7 @@ export interface Interceptors {
90
90
  * NOTE: Error interceptors can transform or replace the error, or throw a new one.
91
91
  * They cannot "recover" from an error to return a successful response data.
92
92
  */
93
- error: Array<(error: APIError) => APIError | Promise<never>>;
93
+ error: Array<(error: APIError) => APIError | Promise<APIError>>;
94
94
  }
95
95
  export type APIResponse<T> = {
96
96
  data: T;
@@ -398,9 +398,23 @@ export interface IMessageAttachment {
398
398
  height?: number;
399
399
  spoiler?: boolean;
400
400
  }
401
+ export type MessageReaction = {
402
+ emoji: string;
403
+ emojiType: "unicode";
404
+ count: number;
405
+ users: string[];
406
+ } | {
407
+ emoji: string;
408
+ emojiType: "custom";
409
+ emojiId: string;
410
+ count: number;
411
+ users: string[];
412
+ emojiName?: string;
413
+ emojiUrl?: string;
414
+ };
401
415
  export interface IMessageServer {
402
416
  messageId: string;
403
- _id?: string;
417
+ _id: string;
404
418
  serverId: string;
405
419
  channelId: string;
406
420
  senderId: string;
@@ -420,9 +434,10 @@ export interface IMessageServer {
420
434
  isWebhook: boolean;
421
435
  webhookUsername?: string;
422
436
  webhookAvatarUrl?: string;
423
- embeds?: IEmbed[];
424
- attachments?: IMessageAttachment[];
425
- interaction?: {
437
+ embeds: IEmbed[];
438
+ attachments: IMessageAttachment[];
439
+ reactions: MessageReaction[];
440
+ interaction: {
426
441
  command: string;
427
442
  options: {
428
443
  name: string;
@@ -432,10 +447,10 @@ export interface IMessageServer {
432
447
  id: string;
433
448
  username: string;
434
449
  };
435
- };
436
- poll?: IPoll;
437
- stickerId?: string;
438
- senderIsBot?: boolean;
450
+ } | null;
451
+ poll: IPoll | null;
452
+ stickerId: string | null;
453
+ senderIsBot: boolean;
439
454
  }
440
455
  export interface IPollInput {
441
456
  title: string;
@@ -835,8 +850,8 @@ export declare class EmbedBuilder {
835
850
  export declare class Message implements IMessageServer {
836
851
  /** Primary message identifier. Normalised from either `messageId` or `_id`. */
837
852
  messageId: string;
838
- /** Legacy MongoDB `_id` field, present on older messages. */
839
- _id?: string;
853
+ /** MongoDB `_id` field. */
854
+ _id: string;
840
855
  /** ID of the server this message belongs to. */
841
856
  serverId: string;
842
857
  /** ID of the channel this message was posted in. */
@@ -871,11 +886,13 @@ export declare class Message implements IMessageServer {
871
886
  /** Avatar URL override for webhook messages. */
872
887
  webhookAvatarUrl?: string;
873
888
  /** Rich embed objects attached to this message. */
874
- embeds?: IEmbed[];
889
+ embeds: IEmbed[];
875
890
  /** Structured file attachments on this message. */
876
- attachments?: IMessageAttachment[];
891
+ attachments: IMessageAttachment[];
892
+ /** Aggregated reaction data on this message. */
893
+ reactions: MessageReaction[];
877
894
  /** Interaction metadata if this message was sent in response to a slash command. */
878
- interaction?: {
895
+ interaction: {
879
896
  command: string;
880
897
  options: {
881
898
  name: string;
@@ -885,11 +902,11 @@ export declare class Message implements IMessageServer {
885
902
  id: string;
886
903
  username: string;
887
904
  };
888
- };
905
+ } | null;
889
906
  /** Poll attached to this message, if any. */
890
- poll?: IPoll;
907
+ poll: IPoll | null;
891
908
  /** Sticker attached to this message, if any. */
892
- stickerId?: string;
909
+ stickerId: string | null;
893
910
  /** Whether the message sender is a bot account. */
894
911
  senderIsBot: boolean;
895
912
  private client;
@@ -1865,6 +1882,9 @@ export declare class Client extends EventEmitter {
1865
1882
  logger: Logger;
1866
1883
  private rest;
1867
1884
  private token;
1885
+ private clientCredentials;
1886
+ private refreshTimer;
1887
+ private refreshPromise;
1868
1888
  constructor(options?: ClientOptions);
1869
1889
  /** Accessor for the application command manager. */
1870
1890
  get application(): {
@@ -1880,6 +1900,12 @@ export declare class Client extends EventEmitter {
1880
1900
  login(token: string, callback?: () => Promise<void>): Promise<void>;
1881
1901
  /** Exchanges client ID/secret for a token and logs in. */
1882
1902
  loginWithSecret(clientId: string, clientSecret: string): Promise<string>;
1903
+ /** Re-exchanges stored client credentials for a fresh access token. */
1904
+ refreshToken(): Promise<string>;
1905
+ private fetchTokenWithSecret;
1906
+ private scheduleTokenRefresh;
1907
+ private getJwtExpirationMs;
1908
+ private reconnectWS;
1883
1909
  /** Connects to the WebSocket gateway. */
1884
1910
  connectWS(): Promise<void>;
1885
1911
  /** Sends a message to a channel. */
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import{EventEmitter as ne}from"events";var H=class extends Error{constructor(e){super(e),this.name="SerchatError"}},m=class extends H{status;data;headers;response;constructor(e,t,s){let r=typeof t=="string"?`"${t}"`:t&&typeof t=="object"&&!Array.isArray(t)&&"message"in t?`"${t.message}"`:JSON.stringify(t);if(super(`Serchat API Error (${e}): ${r}`),this.status=e,this.data=t,this.response=s,this.headers={},this.name="APIError",s){let i=["authorization","cookie","set-cookie","x-csrf-token"];s.headers.forEach((n,o)=>{i.includes(o.toLowerCase())?this.headers[o]="[REDACTED]":this.headers[o]=n})}}},k=class extends m{constructor(e,t){super(400,e,t),this.name="BadRequestError"}},C=class extends m{constructor(e,t){super(401,e,t),this.name="UnauthorizedError"}},S=class extends m{constructor(e,t){super(403,e,t),this.name="ForbiddenError"}},x=class extends m{constructor(e,t){super(404,e,t),this.name="NotFoundError"}},$=class extends m{constructor(e,t){super(429,e,t),this.name="RateLimitError"}},T=class extends m{constructor(e,t){super(500,e,t),this.name="InternalServerError"}},M=class extends m{constructor(e,t){super(502,e,t),this.name="BadGatewayError"}},U=class extends m{constructor(e,t){super(503,e,t),this.name="ServiceUnavailableError"}},A=class extends m{constructor(e,t){super(504,e,t),this.name="GatewayTimeoutError"}};function p({data:a}){if(a===null)throw new Error("Expected data but received empty response (204)");return a}var O=class a{options;_headers;_pending;interceptors={request:[],response:[],error:[]};constructor(e,t){let s=e.baseURL.trim();if(s!==e.baseURL&&console.warn("RESTClient: baseURL contains leading/trailing whitespace"),!s.startsWith("http://")&&!s.startsWith("https://"))throw new Error("baseURL must be an absolute URL starting with http:// or https://");let r=s.endsWith("/")?s:s+"/";this.options={...e,baseURL:r},this._headers=Object.fromEntries(Object.entries(e.headers??{}).filter(([,i])=>i!==void 0)),this._pending=t||new Set}get headers(){return Object.fromEntries(Object.entries(this._headers).filter(e=>e[1]!==void 0))}setDefaultHeader(e,t){t===void 0?delete this._headers[e]:this._headers[e]=t}scoped(e){let t=new a({...this.options,headers:{...this._headers},baseURL:this.buildURL(e)+"/"},this._pending);return t.interceptors.request=this.interceptors.request,t.interceptors.response=this.interceptors.response,t.interceptors.error=this.interceptors.error,t}abortAll(){for(let e of this._pending)e.abort();this._pending.clear()}buildURL(e){let t=new URL(e.replace(/^\/+/,""),this.options.baseURL);if(!t.href.startsWith(this.options.baseURL))throw new Error(`Path "${e}" escapes baseURL`);return t.href}combineSignals(e){if("any"in AbortSignal&&typeof AbortSignal.any=="function")return AbortSignal.any(e);let t=new AbortController,s=[];t.signal.addEventListener("abort",()=>{for(let r of s)r()},{once:!0});for(let r of e){if(r.aborted){t.abort(r.reason);break}let i=()=>t.abort(r.reason);r.addEventListener("abort",i,{once:!0}),s.push(()=>r.removeEventListener("abort",i))}return t.signal}escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}limitResponseBody(e,t){if(!e.body)return e;let s=0,r=t,i=e,n=e.body.pipeThrough(new TransformStream({transform(o,u){s+=o.byteLength,s>r?u.error(new m(413,{error:"Response too large",message:`Body exceeded limit of ${r} bytes`},i)):u.enqueue(o)}}));return new Response(n,{status:e.status,statusText:e.statusText,headers:e.headers})}async request(e,t){let s;try{s=this.buildURL(e)}catch(d){return Promise.reject(d)}let r={...t,url:s,headers:{}},i={},n=d=>{if(d)for(let[f,c]of Object.entries(d))c!==void 0?i[f]=c:delete i[f]};n(this._headers),n(t.headers);let o=["POST","PUT","PATCH","DELETE"].includes(t.method||"GET"),u=new URL(s).origin===(typeof window<"u"?window.location.origin:new URL(this.options.baseURL).origin);if(o&&u&&this.options.csrfCookieName&&this.options.csrfHeaderName){let d=this.getCookie(this.options.csrfCookieName);d&&(i[this.options.csrfHeaderName]=d)}r.headers=i;for(let d of this.interceptors.request)r=d(r);let g=async d=>{let f=t.timeout??this.options.timeout,c=new AbortController;this._pending.add(c);let l;f&&(l=setTimeout(()=>{c.abort(new DOMException("Request timed out","TimeoutError"))},f));let b=r.signal?this.combineSignals([r.signal,c.signal]):c.signal;try{let h=await fetch(r.url,{...r,credentials:this.options.credentials||"same-origin",redirect:this.options.redirect??"error",signal:b});for(let v of this.interceptors.response)h=await v(h);if(this.options.maxResponseBytes!==void 0&&(h=this.limitResponseBody(h,this.options.maxResponseBytes)),!h.ok){let v;if(h.headers.get("Content-Type")?.includes("application/json"))try{v=await h.json()}catch{v=await h.text()}else v=await h.text();let ee=typeof v=="string"?{error:"Non-JSON response",message:v}:v,F=this.mapError(h.status,ee,h),E=this.options.retry;if(E&&d<E.maxAttempts&&(E.retryOn||[429,500,502,503,504]).includes(h.status)){let te=E.backoff?E.backoff(d):1e3*Math.pow(2,d-1);if(await new Promise((se,re)=>{let ie=setTimeout(se,te);c.signal.addEventListener("abort",()=>{clearTimeout(ie),re(c.signal.reason)},{once:!0})}),c.signal.aborted)throw c.signal.reason;return await g(d+1)}let I=F;for(let Y of this.interceptors.error)I=await Y(I);throw I instanceof m||(I=new m(F.status??0,{error:"Interceptor returned invalid error type"},F.response)),I}if(h.status===204)return null;let W;try{W=await h.json()}catch{throw new m(h.status,{error:"Invalid JSON in response"},h)}return this.options.transformResponse?this.options.transformResponse(W,h):W}finally{l&&clearTimeout(l),this._pending.delete(c)}};return g(1)}getCookie(e){if(typeof document>"u")return;let t=document.cookie.match(new RegExp(`(?:^|;\\s*)${this.escapeRegExp(e)}=([^;]*)`));return t?decodeURIComponent(t[1]):void 0}serializeParams(e,t=""){let s=[];for(let[r,i]of Object.entries(e)){let n=t?`${t}[${r}]`:r;if(i!=null)if(Array.isArray(i))for(let[o,u]of i.entries())if(u!==null&&typeof u=="object"){let g=this.serializeParams(u,`${n}[${o}]`);g&&s.push(g)}else s.push(`${encodeURIComponent(n)}=${encodeURIComponent(String(u))}`);else if(typeof i=="object"&&i!==null&&!Array.isArray(i)&&(Object.getPrototypeOf(i)===Object.prototype||Object.getPrototypeOf(i)===null)){let o=this.serializeParams(i,n);o&&s.push(o)}else s.push(`${encodeURIComponent(n)}=${encodeURIComponent(String(i))}`)}return s.join("&")}mapError(e,t,s){switch(e){case 400:return new k(t,s);case 401:return new C(t,s);case 403:return new S(t,s);case 404:return new x(t,s);case 429:return new $(t,s);case 500:return new T(t,s);case 502:return new M(t,s);case 503:return new U(t,s);case 504:return new A(t,s);default:return new m(e,t,s)}}async get(e,t){let s=e;if(t?.params){let i=this.serializeParams(t.params);i&&(s+=(s.includes("?")?"&":"?")+i)}return{data:await this.request(s,{method:"GET",headers:t?.headers,signal:t?.signal,timeout:t?.timeout})}}async mutate(e,t,s,r){let i=s instanceof FormData,n=s instanceof Blob||s instanceof ArrayBuffer||typeof ReadableStream<"u"&&s instanceof ReadableStream,o=s!==void 0&&!i&&!n;return{data:await this.request(t,{method:e,headers:{...o?{"Content-Type":"application/json"}:{},...r?.headers},body:i||n?s:s!==void 0?JSON.stringify(s):void 0,signal:r?.signal,timeout:r?.timeout})}}async post(e,t,s){return this.mutate("POST",e,t,s)}async put(e,t,s){return this.mutate("PUT",e,t,s)}async patch(e,t,s){return this.mutate("PATCH",e,t,s)}async delete(e,t,s){return this.mutate("DELETE",e,t,s)}};import z from"ws";import G from"node:crypto";var y=class{data;constructor(e){this.data=e??{type:"rich"}}setTitle(e){return this.data.title=e,this}setDescription(e){return this.data.description=e,this}setURL(e){return this.data.url=e,this}setColor(e){return this.data.color=e,this}setTimestamp(e=new Date){return e instanceof Date?this.data.timestamp=e.toISOString():typeof e=="number"?this.data.timestamp=new Date(e).toISOString():this.data.timestamp=e,this}setAuthor(e){return this.data.author=e??void 0,this}setFooter(e){return this.data.footer=e??void 0,this}setThumbnail(e,t,s){return this.data.thumbnail=e?{url:e,width:t,height:s}:void 0,this}setImage(e,t,s){return this.data.image=e?{url:e,width:t,height:s}:void 0,this}addFields(...e){return this.data.fields||(this.data.fields=[]),this.data.fields.push(...e),this}setFields(...e){return this.data.fields=e,this}toJSON(){return{...this.data}}};var R=class{messageId;_id;serverId;channelId;senderId;senderUsername;text;createdAt;replyToId;repliedTo;isEdited;isPinned;isSticky;isWebhook;webhookUsername;webhookAvatarUrl;embeds;attachments;interaction;poll;stickerId;senderIsBot;client;constructor(e,t){this.client=e;let s=t.messageId??t._id;if(!s)throw new Error("Message payload is missing both messageId and _id");this.messageId=s,this._id=t._id,this.serverId=t.serverId,this.channelId=t.channelId,this.senderId=t.senderId,this.senderUsername=t.senderUsername,this.text=t.text,this.createdAt=t.createdAt,this.replyToId=t.replyToId,this.repliedTo=t.repliedTo,this.isEdited=t.isEdited,this.isPinned=t.isPinned,this.isSticky=t.isSticky,this.isWebhook=t.isWebhook,this.webhookUsername=t.webhookUsername,this.webhookAvatarUrl=t.webhookAvatarUrl,this.embeds=t.embeds,this.attachments=t.attachments,this.interaction=t.interaction,this.poll=t.poll,this.stickerId=t.stickerId,this.senderIsBot=t.senderIsBot??!1}async reply(e){let t;return e instanceof y?t={embeds:[e.toJSON()],replyToId:this.messageId}:typeof e=="string"?t={content:e,replyToId:this.messageId}:t={...e,replyToId:this.messageId},this.client.sendMessage(this.serverId,this.channelId,t)}async react(e){return this.client.reactToMessage(this.serverId,this.channelId,this.messageId,e)}async delete(){return this.client.deleteMessage(this.serverId,this.channelId,this.messageId)}async vote(e){return this.client.votePoll(this.serverId,this.channelId,this.messageId,e)}hasAttachments(){return Array.isArray(this.attachments)&&this.attachments.length>0}getAttachmentUrl(e){return`${this.client.getApiOrigin()}/api/v1/files/download/${encodeURIComponent(e.attachmentId)}`}getAttachmentsByType(e){return this.attachments?this.attachments.filter(t=>t.type===e):[]}get isEmpty(){return!this.text.trim()}get isOwnMessage(){return this.client.user?.id===this.senderId}get isFromBot(){return this.senderIsBot||this.isOwnMessage}};var P=class{content="";indentation=0;constructor(e="graph TD"){this.content=e+`
1
+ import{EventEmitter as ae}from"events";var H=class extends Error{constructor(e){super(e),this.name="SerchatError"}},m=class extends H{status;data;headers;response;constructor(e,t,s){let r=typeof t=="string"?`"${t}"`:t&&typeof t=="object"&&!Array.isArray(t)&&"message"in t?`"${t.message}"`:JSON.stringify(t);if(super(`Serchat API Error (${e}): ${r}`),this.status=e,this.data=t,this.response=s,this.headers={},this.name="APIError",s){let i=["authorization","cookie","set-cookie","x-csrf-token"];s.headers.forEach((n,o)=>{i.includes(o.toLowerCase())?this.headers[o]="[REDACTED]":this.headers[o]=n})}}},C=class extends m{constructor(e,t){super(400,e,t),this.name="BadRequestError"}},R=class extends m{constructor(e,t){super(401,e,t),this.name="UnauthorizedError"}},S=class extends m{constructor(e,t){super(403,e,t),this.name="ForbiddenError"}},x=class extends m{constructor(e,t){super(404,e,t),this.name="NotFoundError"}},T=class extends m{constructor(e,t){super(429,e,t),this.name="RateLimitError"}},$=class extends m{constructor(e,t){super(500,e,t),this.name="InternalServerError"}},M=class extends m{constructor(e,t){super(502,e,t),this.name="BadGatewayError"}},U=class extends m{constructor(e,t){super(503,e,t),this.name="ServiceUnavailableError"}},A=class extends m{constructor(e,t){super(504,e,t),this.name="GatewayTimeoutError"}};function u({data:a}){if(a===null)throw new Error("Expected data but received empty response (204)");return a}var O=class a{options;_headers;_pending;interceptors={request:[],response:[],error:[]};constructor(e,t){let s=e.baseURL.trim();if(s!==e.baseURL&&console.warn("RESTClient: baseURL contains leading/trailing whitespace"),!s.startsWith("http://")&&!s.startsWith("https://"))throw new Error("baseURL must be an absolute URL starting with http:// or https://");let r=s.endsWith("/")?s:s+"/";this.options={...e,baseURL:r},this._headers=Object.fromEntries(Object.entries(e.headers??{}).filter(([,i])=>i!==void 0)),this._pending=t||new Set}get headers(){return Object.fromEntries(Object.entries(this._headers).filter(e=>e[1]!==void 0))}setDefaultHeader(e,t){t===void 0?delete this._headers[e]:this._headers[e]=t}scoped(e){let t=new a({...this.options,headers:{...this._headers},baseURL:this.buildURL(e)+"/"},this._pending);return t.interceptors.request=this.interceptors.request,t.interceptors.response=this.interceptors.response,t.interceptors.error=this.interceptors.error,t}abortAll(){for(let e of this._pending)e.abort();this._pending.clear()}buildURL(e){let t=new URL(e.replace(/^\/+/,""),this.options.baseURL);if(!t.href.startsWith(this.options.baseURL))throw new Error(`Path "${e}" escapes baseURL`);return t.href}combineSignals(e){if("any"in AbortSignal&&typeof AbortSignal.any=="function")return AbortSignal.any(e);let t=new AbortController,s=[];t.signal.addEventListener("abort",()=>{for(let r of s)r()},{once:!0});for(let r of e){if(r.aborted){t.abort(r.reason);break}let i=()=>t.abort(r.reason);r.addEventListener("abort",i,{once:!0}),s.push(()=>r.removeEventListener("abort",i))}return t.signal}escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}limitResponseBody(e,t){if(!e.body)return e;let s=0,r=t,i=e,n=e.body.pipeThrough(new TransformStream({transform(o,h){s+=o.byteLength,s>r?h.error(new m(413,{error:"Response too large",message:`Body exceeded limit of ${r} bytes`},i)):h.enqueue(o)}}));return new Response(n,{status:e.status,statusText:e.statusText,headers:e.headers})}async request(e,t){let s;try{s=this.buildURL(e)}catch(l){return Promise.reject(l)}let r={...t,url:s,headers:{}},i={},n=l=>{if(l)for(let[f,d]of Object.entries(l))d!==void 0?i[f]=d:delete i[f]};n(this._headers),n(t.headers);let o=["POST","PUT","PATCH","DELETE"].includes(t.method||"GET"),h=new URL(s).origin===(typeof window<"u"?window.location.origin:new URL(this.options.baseURL).origin);if(o&&h&&this.options.csrfCookieName&&this.options.csrfHeaderName){let l=this.getCookie(this.options.csrfCookieName);l&&(i[this.options.csrfHeaderName]=l)}r.headers=i;for(let l of this.interceptors.request)r=l(r);let g=async l=>{let f=t.timeout??this.options.timeout,d=new AbortController;this._pending.add(d);let c;f&&(c=setTimeout(()=>{d.abort(new DOMException("Request timed out","TimeoutError"))},f));let b=r.signal?this.combineSignals([r.signal,d.signal]):d.signal;try{let p=await fetch(r.url,{...r,credentials:this.options.credentials||"same-origin",redirect:this.options.redirect??"error",signal:b});for(let v of this.interceptors.response)p=await v(p);if(this.options.maxResponseBytes!==void 0&&(p=this.limitResponseBody(p,this.options.maxResponseBytes)),!p.ok){let v;if(p.headers.get("Content-Type")?.includes("application/json"))try{v=await p.json()}catch{v=await p.text()}else v=await p.text();let te=typeof v=="string"?{error:"Non-JSON response",message:v}:v,F=this.mapError(p.status,te,p),I=this.options.retry;if(I&&l<I.maxAttempts&&(I.retryOn||[429,500,502,503,504]).includes(p.status)){let re=I.backoff?I.backoff(l):1e3*Math.pow(2,l-1);if(await new Promise((ie,ne)=>{let oe=setTimeout(ie,re);d.signal.addEventListener("abort",()=>{clearTimeout(oe),ne(d.signal.reason)},{once:!0})}),d.signal.aborted)throw d.signal.reason;return await g(l+1)}let P=F,se=typeof r.headers=="object"&&r.headers!==null&&!Array.isArray(r.headers)?r.headers.Authorization:void 0;for(let Q of this.interceptors.error)P=await Q(P);let z=this._headers.Authorization;if(p.status===401&&l<2&&z!==void 0&&z!==se)return r.headers={...r.headers,Authorization:z},await g(l+1);throw P instanceof m||(P=new m(F.status??0,{error:"Interceptor returned invalid error type"},F.response)),P}if(p.status===204)return null;let q;try{q=await p.json()}catch{throw new m(p.status,{error:"Invalid JSON in response"},p)}return this.options.transformResponse?this.options.transformResponse(q,p):q}finally{c&&clearTimeout(c),this._pending.delete(d)}};return g(1)}getCookie(e){if(typeof document>"u")return;let t=document.cookie.match(new RegExp(`(?:^|;\\s*)${this.escapeRegExp(e)}=([^;]*)`));return t?decodeURIComponent(t[1]):void 0}serializeParams(e,t=""){let s=[];for(let[r,i]of Object.entries(e)){let n=t?`${t}[${r}]`:r;if(i!=null)if(Array.isArray(i))for(let[o,h]of i.entries())if(h!==null&&typeof h=="object"){let g=this.serializeParams(h,`${n}[${o}]`);g&&s.push(g)}else s.push(`${encodeURIComponent(n)}=${encodeURIComponent(String(h))}`);else if(typeof i=="object"&&i!==null&&!Array.isArray(i)&&(Object.getPrototypeOf(i)===Object.prototype||Object.getPrototypeOf(i)===null)){let o=this.serializeParams(i,n);o&&s.push(o)}else s.push(`${encodeURIComponent(n)}=${encodeURIComponent(String(i))}`)}return s.join("&")}mapError(e,t,s){switch(e){case 400:return new C(t,s);case 401:return new R(t,s);case 403:return new S(t,s);case 404:return new x(t,s);case 429:return new T(t,s);case 500:return new $(t,s);case 502:return new M(t,s);case 503:return new U(t,s);case 504:return new A(t,s);default:return new m(e,t,s)}}async get(e,t){let s=e;if(t?.params){let i=this.serializeParams(t.params);i&&(s+=(s.includes("?")?"&":"?")+i)}return{data:await this.request(s,{method:"GET",headers:t?.headers,signal:t?.signal,timeout:t?.timeout})}}async mutate(e,t,s,r){let i=s instanceof FormData,n=s instanceof Blob||s instanceof ArrayBuffer||typeof ReadableStream<"u"&&s instanceof ReadableStream,o=s!==void 0&&!i&&!n;return{data:await this.request(t,{method:e,headers:{...o?{"Content-Type":"application/json"}:{},...r?.headers},body:i||n?s:s!==void 0?JSON.stringify(s):void 0,signal:r?.signal,timeout:r?.timeout})}}async post(e,t,s){return this.mutate("POST",e,t,s)}async put(e,t,s){return this.mutate("PUT",e,t,s)}async patch(e,t,s){return this.mutate("PATCH",e,t,s)}async delete(e,t,s){return this.mutate("DELETE",e,t,s)}};import G from"ws";import Y from"node:crypto";var y=class{data;constructor(e){this.data=e??{type:"rich"}}setTitle(e){return this.data.title=e,this}setDescription(e){return this.data.description=e,this}setURL(e){return this.data.url=e,this}setColor(e){return this.data.color=e,this}setTimestamp(e=new Date){return e instanceof Date?this.data.timestamp=e.toISOString():typeof e=="number"?this.data.timestamp=new Date(e).toISOString():this.data.timestamp=e,this}setAuthor(e){return this.data.author=e??void 0,this}setFooter(e){return this.data.footer=e??void 0,this}setThumbnail(e,t,s){return this.data.thumbnail=e?{url:e,width:t,height:s}:void 0,this}setImage(e,t,s){return this.data.image=e?{url:e,width:t,height:s}:void 0,this}addFields(...e){return this.data.fields||(this.data.fields=[]),this.data.fields.push(...e),this}setFields(...e){return this.data.fields=e,this}toJSON(){return{...this.data}}};var w=class{messageId;_id;serverId;channelId;senderId;senderUsername;text;createdAt;replyToId;repliedTo;isEdited;isPinned;isSticky;isWebhook;webhookUsername;webhookAvatarUrl;embeds;attachments;reactions;interaction;poll;stickerId;senderIsBot;client;constructor(e,t){this.client=e;let s=t.messageId??t._id;if(!s)throw new Error("Message payload is missing both messageId and _id");this.messageId=s,this._id=t._id??s,this.serverId=t.serverId,this.channelId=t.channelId,this.senderId=t.senderId,this.senderUsername=t.senderUsername,this.text=t.text,this.createdAt=t.createdAt,this.replyToId=t.replyToId,this.repliedTo=t.repliedTo,this.isEdited=t.isEdited,this.isPinned=t.isPinned,this.isSticky=t.isSticky,this.isWebhook=t.isWebhook,this.webhookUsername=t.webhookUsername,this.webhookAvatarUrl=t.webhookAvatarUrl,this.embeds=t.embeds??[],this.attachments=t.attachments??[],this.reactions=t.reactions??[],this.interaction=t.interaction??null,this.poll=t.poll??null,this.stickerId=t.stickerId??null,this.senderIsBot=t.senderIsBot??!1}async reply(e){let t;return e instanceof y?t={embeds:[e.toJSON()],replyToId:this.messageId}:typeof e=="string"?t={content:e,replyToId:this.messageId}:t={...e,replyToId:this.messageId},this.client.sendMessage(this.serverId,this.channelId,t)}async react(e){return this.client.reactToMessage(this.serverId,this.channelId,this.messageId,e)}async delete(){return this.client.deleteMessage(this.serverId,this.channelId,this.messageId)}async vote(e){return this.client.votePoll(this.serverId,this.channelId,this.messageId,e)}hasAttachments(){return Array.isArray(this.attachments)&&this.attachments.length>0}getAttachmentUrl(e){return`${this.client.getApiOrigin()}/api/v1/files/download/${encodeURIComponent(e.attachmentId)}`}getAttachmentsByType(e){return this.attachments.filter(t=>t.type===e)}get isEmpty(){return!this.text.trim()}get isOwnMessage(){return this.client.user?.id===this.senderId}get isFromBot(){return this.senderIsBot||this.isOwnMessage}};var k=class{content="";indentation=0;constructor(e="graph TD"){this.content=e+`
2
2
  `}get indent(){return" ".repeat(this.indentation)}add(e){return this.content+=`${this.indent}${e}
3
- `,this}node(e,t,s="box"){if(!t)return this.add(e),this;let r={box:["[","]"],round:["(",")"],stadium:["([","])"],subroutine:["[[","]]"],cylindrical:["[(",")]"],circle:["((","))"],asymmetric:[">","]"],rhombus:["{","}"],hexagon:["{{","}}"]},[i,n]=r[s]||r.box;return this.add(`${e}${i}"${t}"${n}`),this}edge(e,t,s,r="arrow"){let i={arrow:"-->",line:"---",dotted:"-.->",thick:"==>"},n=i[r]||i.arrow;return s?this.add(`${e} ${n}|"${s}"| ${t}`):this.add(`${e} ${n} ${t}`),this}subgraph(e,t){return this.add(`subgraph "${e}"`),this.indentation++,t(this),this.indentation--,this.add("end"),this}style(e,t){return this.add(`style ${e} ${t}`),this}comment(e){return this.add(`%% ${e}`),this}build(){return this.content.trim()}toString(){return this.build()}};var j=class{content="";constructor(e=""){this.content=e}wrap(e,t,s){return this.content+=e+s+t,this}text(e){return this.content+=e,this}italic(e){return this.wrap("*","*",e)}bold(e){return this.wrap("**","**",e)}boldItalic(e){return this.wrap("***","***",e)}strikethrough(e){return this.wrap("~~","~~",e)}underline(e){return this.wrap("__","__",e)}doubleUnderline(e){return this.wrap("___","___",e)}curlyUnderline(e){return this.wrap("_~","~_",e)}jaggedUnderline(e){return this.wrap("_^","^_",e)}doubleCurlyUnderline(e){return this.wrap("_~~","~~_",e)}dashedUnderline(e){return this.wrap("_-","-_",e)}dottedUnderline(e){return this.wrap("_.","._",e)}rhythmUnderline(e){return this.wrap("_-.",".-_",e)}spoiler(e){return this.wrap("||","||",e)}inlineCode(e){return this.wrap("`","`",e)}inlineLatex(e){return this.wrap("$$","$$",e)}superscript(e){return this.wrap("^","^",e)}subscript(e){return this.wrap("~","~",e)}stackedScript(e,t){return this.content+=`^${e}|${t}^`,this}link(e,t){return this.content+=`[${e}](${t})`,this}userMention(e){return this.content+=`<userid:'${e}'>`,this}roleMention(e){return this.content+=`<roleid:'${e}'>`,this}channelMention(e,t){return this.content+=`https://catfla.re/chat/@server/${e}/channel/${t}`,this}everyoneMention(){return this.content+="<everyone>",this}customEmoji(e){return this.content+=`<emoji:${e}>`,this}build(){return this.content}toString(){return this.content}},w=class extends j{p(e){if(typeof e=="string")this.content+=e+`
3
+ `,this}node(e,t,s="box"){if(!t)return this.add(e),this;let r={box:["[","]"],round:["(",")"],stadium:["([","])"],subroutine:["[[","]]"],cylindrical:["[(",")]"],circle:["((","))"],asymmetric:[">","]"],rhombus:["{","}"],hexagon:["{{","}}"]},[i,n]=r[s]||r.box;return this.add(`${e}${i}"${t}"${n}`),this}edge(e,t,s,r="arrow"){let i={arrow:"-->",line:"---",dotted:"-.->",thick:"==>"},n=i[r]||i.arrow;return s?this.add(`${e} ${n}|"${s}"| ${t}`):this.add(`${e} ${n} ${t}`),this}subgraph(e,t){return this.add(`subgraph "${e}"`),this.indentation++,t(this),this.indentation--,this.add("end"),this}style(e,t){return this.add(`style ${e} ${t}`),this}comment(e){return this.add(`%% ${e}`),this}build(){return this.content.trim()}toString(){return this.build()}};var j=class{content="";constructor(e=""){this.content=e}wrap(e,t,s){return this.content+=e+s+t,this}text(e){return this.content+=e,this}italic(e){return this.wrap("*","*",e)}bold(e){return this.wrap("**","**",e)}boldItalic(e){return this.wrap("***","***",e)}strikethrough(e){return this.wrap("~~","~~",e)}underline(e){return this.wrap("__","__",e)}doubleUnderline(e){return this.wrap("___","___",e)}curlyUnderline(e){return this.wrap("_~","~_",e)}jaggedUnderline(e){return this.wrap("_^","^_",e)}doubleCurlyUnderline(e){return this.wrap("_~~","~~_",e)}dashedUnderline(e){return this.wrap("_-","-_",e)}dottedUnderline(e){return this.wrap("_.","._",e)}rhythmUnderline(e){return this.wrap("_-.",".-_",e)}spoiler(e){return this.wrap("||","||",e)}inlineCode(e){return this.wrap("`","`",e)}inlineLatex(e){return this.wrap("$$","$$",e)}superscript(e){return this.wrap("^","^",e)}subscript(e){return this.wrap("~","~",e)}stackedScript(e,t){return this.content+=`^${e}|${t}^`,this}link(e,t){return this.content+=`[${e}](${t})`,this}userMention(e){return this.content+=`<userid:'${e}'>`,this}roleMention(e){return this.content+=`<roleid:'${e}'>`,this}channelMention(e,t){return this.content+=`https://catfla.re/chat/@server/${e}/channel/${t}`,this}everyoneMention(){return this.content+="<everyone>",this}customEmoji(e){return this.content+=`<emoji:${e}>`,this}build(){return this.content}toString(){return this.content}},E=class extends j{p(e){if(typeof e=="string")this.content+=e+`
4
4
  `;else{let t=new j;e(t),this.content+=t.build()+`
5
5
  `}return this}h1(e){return this.content+=`# ${e}
6
6
  `,this}h2(e){return this.content+=`## ${e}
@@ -27,6 +27,6 @@ $
27
27
  `;return this}table(e,t){this.content+=`| ${e.join(" | ")} |
28
28
  `,this.content+=`| ${e.map(()=>"---").join(" | ")} |
29
29
  `;for(let s of t)this.content+=`| ${s.join(" | ")} |
30
- `;return this}mermaid(e){if(typeof e=="string")return this.codeBlock("mermaid",e);if(e instanceof P)return this.codeBlock("mermaid",e.build());{let t=new P;return e(t),this.codeBlock("mermaid",t.build())}}file(e){return this.content+=`[%file%](${e})
31
- `,this}};var _=class{command;commandId;options;serverId;channelId;senderId;senderUsername;permissions;invocationId;client;constructor(e,t){this.client=e,this.command=t.command,this.commandId=t.commandId,this.options=t.options,this.serverId=t.serverId,this.channelId=t.channelId,this.senderId=t.senderId,this.senderUsername=t.senderUsername,this.permissions=t.senderPermissions||{},this.invocationId=t.invocationId}getOption(e){return this.options.find(t=>t.name===e)}getTypedOption(e,t){let s=this.getOption(e);return typeof s?.value===t?s?.value:void 0}getString(e){return this.getTypedOption(e,"string")}getInteger(e){return this.getTypedOption(e,"number")}getBoolean(e){return this.getTypedOption(e,"boolean")}getUser(e){return this.getString(e)}getChannel(e){return this.getString(e)}getRole(e){return this.getString(e)}hasPermission(e){return this.permissions.administrator?!0:!!this.permissions[e]}async reply(e){let t;return e instanceof y?t={embeds:[e.toJSON()]}:e instanceof w?t={content:e.build()}:typeof e=="string"?t={content:e}:(t={...e},t.embeds&&(t.embeds=t.embeds.map(s=>s instanceof y?s.toJSON():s))),t.interaction={command:this.command,options:this.options.map(s=>({name:s.name,value:s.value})),user:{id:this.senderId,username:this.senderUsername}},this.client.sendMessage(this.serverId,this.channelId,t)}};var B=class{ws=null;client;pendingRequests=new Map;constructor(e){this.client=e}reconnectAttempts=0;reconnectTimeout=null;connectionPromise=null;connectionResolve=null;connectionReject=null;heartbeatInterval=null;heartbeatTimeout=null;heartbeatRequestId=null;heartbeatIntervalMs=3e4;heartbeatTimeoutMs=1e4;async connect(){return this.connectionPromise?this.connectionPromise:(this.connectionPromise=new Promise((e,t)=>{this.connectionResolve=e,this.connectionReject=t,this._connect()}),this.connectionPromise)}_connect(){if(!this.client.getToken()){let s=new Error("Client is not logged in.");this.connectionReject&&(this.connectionReject(s),this.connectionPromise=null,this.connectionResolve=null,this.connectionReject=null);return}let t=(this.client.options.apiBaseUrl||"https://ser.chat/api/v1").replace(/^http/,"ws").replace(/\/api\/v1\/?$/,"/ws");this.client.logger.info(`Connecting to WebSocket at ${t}...`),this.ws&&(this.stopHeartbeat(),this.ws.removeAllListeners(),this.ws.close()),this.ws=new z(t),this.ws.on("open",()=>{let s=G.randomUUID();this.ws.send(JSON.stringify({id:s,event:{type:"authenticate",payload:{token:this.client.getToken()}}}))}),this.ws.on("message",s=>{let r;try{r=JSON.parse(s.toString())}catch{return}if(r.event?.type==="authenticated"&&r.event.payload&&(this.client.user=r.event.payload.user,this.reconnectAttempts=0,this.startHeartbeat(),this.connectionResolve&&(this.connectionResolve(),this.connectionResolve=null,this.connectionReject=null),this.client.logger.info(`Authenticated as ${r.event.payload.user.username} (${r.event.payload.user.id})`),this.client.isReady?this.client.emit("reconnected"):(this.client.isReady=!0,this.client.emit("ready",r.event.payload.user))),r.event?.type==="pong"&&this.handleHeartbeatPong(r),r.meta?.replyTo&&this.pendingRequests.has(r.meta.replyTo)){let n=this.pendingRequests.get(r.meta.replyTo);if(this.pendingRequests.delete(r.meta.replyTo),clearTimeout(n.timeout),r.event?.type==="error"&&r.event.payload){let o=r.event.payload.details;n.reject(new Error(`WebSocket Error [${r.event.payload.code}]: ${o?.message}`))}else r.event?.payload&&n.resolve(r.event.payload)}let i=r.event;if(i)switch(i.type){case"message_server":this.client.emit("messageCreate",new R(this.client,i.payload));break;case"interaction_create_server":this.client.emit("interactionCreate",new _(this.client,i.payload));break;case"message_server_edited":this.client.emit("messageUpdate",i.payload);break;case"message_server_deleted":this.client.emit("messageDelete",i.payload);break;case"messages_server_bulk_deleted":this.client.emit("messageBulkDelete",i.payload);break;case"reaction_added":this.client.emit("messageReactionAdd",i.payload);break;case"reaction_removed":this.client.emit("messageReactionRemove",i.payload);break;case"poll_vote_updated_server":case"poll_vote_updated_dm":this.client.emit("pollVoteUpdate",i.payload);break;case"member_added":this.client.emit("serverMemberAdd",i.payload);break;case"member_removed":this.client.emit("serverMemberRemove",i.payload);break;case"member_updated":this.client.emit("serverMemberUpdate",i.payload);break;case"channel_created":this.client.emit("channelCreate",i.payload);break;case"channel_updated":this.client.emit("channelUpdate",i.payload);break;case"channel_deleted":this.client.emit("channelDelete",i.payload);break;case"channels_reordered":this.client.emit("channelsReordered",i.payload);break;case"category_created":this.client.emit("categoryCreate",i.payload);break;case"category_updated":this.client.emit("categoryUpdate",i.payload);break;case"category_deleted":this.client.emit("categoryDelete",i.payload);break;case"categories_reordered":this.client.emit("categoriesReordered",i.payload);break;case"channel_permissions_updated":this.client.emit("channelPermissionsUpdate",i.payload);break;case"category_permissions_updated":this.client.emit("categoryPermissionsUpdate",i.payload);break;case"server_updated":this.client.emit("serverUpdate",i.payload);break;case"server_deleted":this.client.emit("serverDelete",i.payload);break;case"server_icon_updated":this.client.emit("serverIconUpdate",i.payload);break;case"server_banner_updated":this.client.emit("serverBannerUpdate",i.payload);break;case"role_created":this.client.emit("roleCreate",i.payload);break;case"role_updated":this.client.emit("roleUpdate",i.payload);break;case"role_deleted":this.client.emit("roleDelete",i.payload);break;case"roles_reordered":this.client.emit("rolesReordered",i.payload);break;case"server_invite_created":this.client.emit("inviteCreate",i.payload);break;case"server_invite_deleted":this.client.emit("inviteDelete",i.payload);break;case"member_banned":this.client.emit("serverMemberBan",i.payload);break;case"member_unbanned":this.client.emit("serverMemberUnban",i.payload);break;case"ownership_transferred":this.client.emit("ownershipTransfer",i.payload);break;case"presence_sync":this.client.emit("presenceSync",i.payload);break;case"user_online":this.client.emit("userOnline",i.payload);break;case"user_offline":this.client.emit("userOffline",i.payload);break;case"user_updated":this.client.emit("userUpdate",i.payload);break;case"error":case"ping":case"pong":case"authenticated":case"server_joined":break}}),this.ws.on("error",s=>{this.client.logger.error(`WebSocket error: ${s.message}`),this.stopHeartbeat(),this.connectionReject&&(this.connectionReject(s),this.connectionPromise=null,this.connectionResolve=null,this.connectionReject=null)}),this.ws.on("close",(s,r)=>{this.stopHeartbeat(),this.client.logger.warn(`WebSocket connection closed. Code: ${s}, Reason: ${r?r.toString():"None"}`),this.client.emit("disconnect"),this.connectionReject&&(this.connectionReject(new Error(`WebSocket closed before authentication. Code: ${s}, Reason: ${r?r.toString():"None"}`)),this.connectionPromise=null,this.connectionResolve=null,this.connectionReject=null),this.scheduleReconnect()})}startHeartbeat(){this.stopHeartbeat(),this.heartbeatInterval=setInterval(()=>{this.sendHeartbeat()},this.heartbeatIntervalMs),this.heartbeatInterval.unref(),this.sendHeartbeat()}stopHeartbeat(){this.heartbeatInterval!==null&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null),this.heartbeatTimeout!==null&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=null),this.heartbeatRequestId=null}sendHeartbeat(){if(!this.ws||this.ws.readyState!==z.OPEN||this.heartbeatRequestId!==null)return;let e=G.randomUUID();this.heartbeatRequestId=e,this.ws.send(JSON.stringify({id:e,event:{type:"ping",payload:{}}})),this.heartbeatTimeout=setTimeout(()=>{this.client.logger.warn("WebSocket heartbeat timed out; reconnecting..."),this.heartbeatTimeout=null,this.heartbeatRequestId=null,this.ws?.terminate()},this.heartbeatTimeoutMs),this.heartbeatTimeout.unref()}handleHeartbeatPong(e){this.heartbeatRequestId!==null&&e.meta?.replyTo===this.heartbeatRequestId&&(this.heartbeatRequestId=null,this.heartbeatTimeout!==null&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=null))}scheduleReconnect(){if(this.reconnectTimeout)return;let e=Math.min(1e3*Math.pow(2,this.reconnectAttempts),3e4);this.client.logger.info(`Scheduling reconnection in ${e}ms (attempt ${this.reconnectAttempts+1})`),this.reconnectAttempts++,this.reconnectTimeout=setTimeout(()=>{this.reconnectTimeout=null,this._connect()},e)}async joinServer(e){if(!this.ws||this.ws.readyState!==z.OPEN)throw new Error("WebSocket is not connected.");let t=G.randomUUID();return new Promise((s,r)=>{let i=setTimeout(()=>{this.pendingRequests.delete(t),r(new Error("Request timeout"))},5e3);this.pendingRequests.set(t,{resolve:s,reject:r,timeout:i}),this.ws.send(JSON.stringify({id:t,event:{type:"join_server",payload:{serverId:e}}}))})}};var J=class{rest;registeredCommands=new Map;registeredCommandsById=new Map;constructor(e){this.rest=e}register(e){if(this.registeredCommands.has(e.name))throw new Error(`Command with name "${e.name}" is already registered.`);this.registeredCommands.set(e.name,e)}async handleInteraction(e){let t;e.commandId?t=this.registeredCommandsById.get(e.commandId):t=this.registeredCommands.get(e.command),t&&await t.execute(e)}getCommandsData(){return Array.from(this.registeredCommands.values()).map(e=>e.toJSON())}async sync(){await this.set(this.getCommandsData())}async set(e){let t=new Set;for(let i of e){if(t.has(i.name))throw new Error(`Duplicate command name found in set(): "${i.name}"`);t.add(i.name)}let s=await this.rest.put("/applications/@me/commands",{commands:e}),r=p(s);this.registeredCommandsById.clear();for(let i of r){let n=this.registeredCommands.get(i.name);n&&i.id&&(n.id=i.id,this.registeredCommandsById.set(i.id,n))}return r}};var D=class{rest;constructor(e){this.rest=e}async getStickers(){let e=await this.rest.get("/stickers");return p(e)}async getServerStickers(e){let t=await this.rest.get(`/servers/${e}/stickers`);return p(t)}async createSticker(e,t){let s=await this.rest.post(`/servers/${e}/stickers`,t);return p(s)}async deleteSticker(e,t){await this.rest.delete(`/servers/${e}/stickers/${t}`)}};var N=class{rest;constructor(e){this.rest=e}embedToJSON(e){return{type:e.type,color:e.color,title:e.title,url:e.url,description:e.description,timestamp:e.timestamp,author:e.author?{name:e.author.name,url:e.author.url,icon_url:e.author.icon_url}:void 0,footer:e.footer?{text:e.footer.text,icon_url:e.footer.icon_url}:void 0,thumbnail:e.thumbnail?{url:e.thumbnail.url,width:e.thumbnail.width,height:e.thumbnail.height}:void 0,image:e.image?{url:e.image.url,width:e.image.width,height:e.image.height}:void 0,video:e.video?{url:e.video.url,width:e.video.width,height:e.video.height}:void 0,provider:e.provider?{name:e.provider.name,url:e.provider.url}:void 0,fields:e.fields?.map(t=>({name:t.name,value:t.value,inline:t.inline}))}}async getWebhooks(e,t){let s=await this.rest.get(`/servers/${e}/channels/${t}/webhooks`);return p(s)}async createWebhook(e,t,s){let r={name:s.name,avatarUrl:s.avatarUrl},i=await this.rest.post(`/servers/${e}/channels/${t}/webhooks`,r);return p(i)}async deleteWebhook(e,t,s){await this.rest.delete(`/servers/${e}/channels/${t}/webhooks/${s}`)}async uploadWebhookAvatar(e,t,s,r){let i=new FormData;i.append("avatar",r);let n=await this.rest.post(`/servers/${e}/channels/${t}/webhooks/${s}/avatar`,i);return p(n)}async executeWebhook(e,t){let s={content:t.content,username:t.username,avatarUrl:t.avatarUrl,noEmbedsUrls:t.noEmbedsUrls?.slice(0,25),embeds:t.embeds?.map(i=>this.embedToJSON(i))},r=await this.rest.post(`/webhooks/${e}`,s);return p(r)}async editWebhookMessage(e,t,s){let r={content:s.content,username:s.username,avatarUrl:s.avatarUrl,noEmbedsUrls:s.noEmbedsUrls?.slice(0,25),embeds:s.embeds?.map(i=>this.embedToJSON(i))};await this.rest.patch(`/webhooks/${e}/messages/${t}`,r)}async deleteWebhookMessage(e,t){await this.rest.delete(`/webhooks/${e}/messages/${t}`)}};var V=class{listeners={};logger;errorEvent;subscriberListeners=new Map;constructor(e={}){this.logger=e.logger,this.errorEvent=e.errorEvent}register(e){if(!e||typeof e!="object")return;let t={},s=this.getMethods(e);for(let r of s)if(typeof r=="string"){let i=this.getEventNamesForCallback(r);for(let n of i){let o=e[r];if(typeof o=="function"){let u=o,g=(...f)=>{try{let c=u(...f);return c instanceof Promise&&c.catch(l=>{let b=l instanceof Error?l:new Error(String(l));this.handleListenerError(n,b)}),c}catch(c){let l=c instanceof Error?c:new Error(String(c));this.handleListenerError(n,l)}};this.on(n,g);let d=t[n];d||(d=new Set,t[n]=d),d.add(g)}}}Object.keys(t).length>0&&this.subscriberListeners.set(e,t)}unregister(e){let t=this.subscriberListeners.get(e);if(t){for(let s of Object.keys(t)){let r=t[s];if(r)for(let i of r)this.off(s,i)}this.subscriberListeners.delete(e)}}getEventNamesForCallback(e){if(!e.startsWith("on")||e.length<=2)return[];let t=e.slice(2),r=[t.charAt(0).toLowerCase()+t.slice(1)];return e==="onMessage"&&r.push("messageCreate"),e==="onMessageCreate"&&r.push("messageCreate"),e==="onInteraction"&&r.push("interactionCreate"),e==="onInteractionCreate"&&r.push("interactionCreate"),r}getMethods(e){let t=[],s=e;for(;s&&s!==Object.prototype;){let r=Object.getOwnPropertyNames(s);for(let i of r)if(i!=="constructor"&&typeof e[i]=="function"){let o=i;t.includes(o)||t.push(o)}s=Object.getPrototypeOf(s)}return t}on(e,t){let s=this.listeners[e];return s||(s=new Set,this.listeners[e]=s),s.add(t),this}once(e,t){let s=(...r)=>(this.off(e,s),t(...r));return this.on(e,s)}off(e,t){return this.listeners[e]?.delete(t),this}emit(e,...t){let s=this.listeners[e];if(!s||s.size===0)return!1;for(let r of s)try{let i=r(...t);i instanceof Promise&&i.catch(n=>{let o=n instanceof Error?n:new Error(String(n));this.handleListenerError(e,o)})}catch(i){let n=i instanceof Error?i:new Error(String(i));this.handleListenerError(e,n)}return!0}handleListenerError(e,t){this.logger?.error(`Event listener for "${String(e)}" failed: ${t.message}`),this.errorEvent&&e!==this.errorEvent&&this.emitError(t)}emitError(e){this.errorEvent&&this.emit(this.errorEvent,e)}};var L=class{client;registeredModules=new Map;constructor(e){this.client=e}async register(e){if(this.registeredModules.has(e.name))throw new Error(`Module with name "${e.name}" is already registered.`);e.register&&await e.register(this.client),this.client.events.register(e),this.registeredModules.set(e.name,e)}};var K=class{title="";options=[];multiSelect=!1;expiresAt;setTitle(e){return this.title=e,this}addOption(e,t){return this.options.push({text:e,emoji:t,emojiType:t?"unicode":void 0}),this}addCustomEmojiOption(e,t){return this.options.push({text:e,emojiId:t,emojiType:"custom"}),this}setMultiSelect(e){return this.multiSelect=e,this}setExpiresAt(e){return this.expiresAt=typeof e=="string"?e:e.toISOString(),this}toJSON(){return{title:this.title,options:this.options,multiSelect:this.multiSelect,expiresAt:this.expiresAt}}};var Q=(n=>(n[n.DEBUG=0]="DEBUG",n[n.INFO=1]="INFO",n[n.WARN=2]="WARN",n[n.ERROR=3]="ERROR",n[n.CRITICAL=4]="CRITICAL",n[n.NONE=5]="NONE",n))(Q||{}),q=class{level=1;constructor(e=1){this.level=e}getRegion(){let e=new Error().stack;if(!e)return"unknown";let s=e.split(`
32
- `)[4];if(!s)return"unknown";let r=s.match(/(?:at\s+)?(?:.*\((.*)\)|at\s+(.*))/),n=(r?.[1]||r?.[2]||"unknown").split("/");return n[n.length-1]||"unknown"}format(e,t){let s=e.toLowerCase(),r={reset:"\x1B[0m",gray:"\x1B[90m",blue:"\x1B[34m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",magenta:"\x1B[35m",cyan:"\x1B[36m",bold:"\x1B[1m"},i={debug:r.blue,info:r.green,warning:r.yellow,error:r.red,critical:r.magenta+r.bold}[s]||r.reset,n=`${r.cyan}[sdk]${r.reset}`,o=`${r.gray}[${this.getRegion()}]${r.reset}`,u=`${i}[${s}]${r.reset}`,g=`${r.gray}[${new Date().toISOString()}]${r.reset}`;return`${n} ${o} ${u} ${g} - ${t}`}debug(e){this.level<=0&&console.debug(this.format("debug",e))}info(e){this.level<=1&&console.info(this.format("info",e))}warn(e){this.level<=2&&console.warn(this.format("warning",e))}error(e){this.level<=3&&console.error(this.format("error",e))}critical(e){this.level<=4&&console.error(this.format("critical",e))}};var X=class extends ne{ws;commands;stickers;webhooks;events;modules;user=null;isReady=!1;options;logger;rest;token=null;constructor(e={}){super(),this.options={apiBaseUrl:"https://ser.chat/api/v1",logLevel:1,...e},this.logger=new q(this.options.logLevel),this.rest=new O({baseURL:this.options.apiBaseUrl}),this.events=new V({logger:this.logger,errorEvent:"error"}),this.ws=new B(this),this.commands=new J(this.rest),this.stickers=new D(this.rest),this.webhooks=new N(this.rest),this.modules=new L(this),this.events.on("interactionCreate",t=>{this.commands.handleInteraction(t).catch(console.error)})}on(e,t){return this.events.on(e,t),this}once(e,t){return this.events.once(e,t),this}off(e,t){return this.events.off(e,t),this}emit(e,...t){return this.events.emit(e,...t)}get application(){return{commands:this.commands}}getToken(){return this.token}getRest(){return this.rest}getApiOrigin(){try{return new URL(this.options.apiBaseUrl).origin}catch{return this.options.apiBaseUrl}}async login(e,t){this.logger.info("Logging in with token..."),this.token=e,this.rest.setDefaultHeader("Authorization",`Bearer ${e}`),await this.connectWS(),t&&await t()}async loginWithSecret(e,t){let s=await this.rest.post("/bots/token",{client_id:e,client_secret:t}),r=p(s).token;return await this.login(r),r}async connectWS(){await this.ws.connect()}async sendMessage(e,t,s){if(!this.token)throw new Error("Client is not logged in.");let r;s instanceof y?r={embeds:[s.toJSON()]}:s instanceof w?r={content:s.build()}:s instanceof K?r={poll:s.toJSON()}:typeof s=="string"?r={content:s}:(r={...s},r.embeds&&(r.embeds=r.embeds.map(n=>n instanceof y?n.toJSON():n)),r.noEmbedsUrls&&(r.noEmbedsUrls=r.noEmbedsUrls.slice(0,25)),r.poll&&"toJSON"in r.poll&&(r.poll=r.poll.toJSON()));let i=await this.rest.post(`/servers/${e}/channels/${t}/messages`,r);return new R(this,p(i))}async votePoll(e,t,s,r){if(!this.token)throw new Error("Client is not logged in.");await this.rest.post(`/servers/${e}/channels/${t}/messages/${s}/poll/vote`,{id:r})}async getMessages(e,t,s=50){if(!this.token)throw new Error("Client is not logged in.");let r=await this.rest.get(`/servers/${e}/channels/${t}/messages`,{params:{limit:s}});return p(r).map(i=>new R(this,i))}async bulkDeleteMessages(e,t,s){if(!this.token)throw new Error("Client is not logged in.");let r=await this.rest.post(`/servers/${e}/channels/${t}/messages/bulk-delete`,{messageIds:s});return p(r).deletedCount}async reactToMessage(e,t,s,r){if(!this.token)throw new Error("Client is not logged in.");await this.rest.post(`/servers/${e}/channels/${t}/messages/${s}/reactions`,{emoji:r})}async deleteMessage(e,t,s){if(!this.token)throw new Error("Client is not logged in.");await this.rest.delete(`/servers/${e}/channels/${t}/messages/${s}`)}async banMember(e,t,s,r=0){if(!this.token)throw new Error("Client is not logged in.");await this.rest.post(`/servers/${e}/bans`,{userId:t,reason:s??null,deleteMessageDays:r})}async unbanMember(e,t,s){if(!this.token)throw new Error("Client is not logged in.");await this.rest.delete(`/servers/${e}/bans/${t}`,{data:{reason:s??null}})}async kickMember(e,t,s){if(!this.token)throw new Error("Client is not logged in.");await this.rest.delete(`/servers/${e}/members/${t}`,{data:{reason:s??null}})}async timeoutMember(e,t,s,r){if(!this.token)throw new Error("Client is not logged in.");await this.rest.post(`/servers/${e}/members/${t}/timeout`,{duration:s,reason:r??null})}async updateChannel(e,t,s){if(!this.token)throw new Error("Client is not logged in.");await this.rest.patch(`/servers/${e}/channels/${t}`,s)}async getServer(e){if(!this.token)throw new Error("Client is not logged in.");let t=await this.rest.get(`/servers/${e}`);return p(t)}async getChannelStats(e,t){if(!this.token)throw new Error("Client is not logged in.");let s=await this.rest.get(`/servers/${e}/channels/${t}/stats`);return p(s)}async getServerStats(e){if(!this.token)throw new Error("Client is not logged in.");let t=await this.rest.get(`/servers/${e}/stats`);return p(t)}async getRoles(e){if(!this.token)throw new Error("Client is not logged in.");let t=await this.rest.get(`/servers/${e}/roles`);return p(t)}async hasPermission(e,t,s){try{let r=await this.getServer(e);if(r&&(r.ownerId===t||r._id===t))return!0;let[i,n]=await Promise.all([this.rest.get(`/servers/${e}/members/${t}`),this.getRoles(e)]),o=p(i),u=o&&typeof o=="object"&&"roles"in o?o.roles:o&&typeof o=="object"&&"member"in o?o.member.roles:[];if(!Array.isArray(u))return!1;let g=n.find(l=>l.name==="@everyone"),d=new Set(u);g&&d.add(g.id||g._id);let f=n.filter(l=>d.has(l.id||l._id)).sort((l,b)=>l.position-b.position);for(let l of f){let b=typeof l.permissions=="string"?JSON.parse(l.permissions):l.permissions;if(b&&b.administrator===!0)return!0}let c=!1;for(let l of f){let b=typeof l.permissions=="string"?JSON.parse(l.permissions):l.permissions;b&&typeof b[s]=="boolean"&&(c=b[s])}return c}catch(r){this.logger.error(`Failed to check permission: ${r}`)}return!1}};var oe=(o=>(o[o.SUB_COMMAND=1]="SUB_COMMAND",o[o.STRING=3]="STRING",o[o.INTEGER=4]="INTEGER",o[o.BOOLEAN=5]="BOOLEAN",o[o.USER=6]="USER",o[o.CHANNEL=7]="CHANNEL",o[o.ROLE=8]="ROLE",o))(oe||{});var Ye=["viewChannels","sendMessages","addReactions","connect","manageMessages","deleteMessagesOfOthers","manageChannels","manageRoles","banMembers","kickMembers","manageInvites","manageServer","administrator","manageWebhooks","pingRolesAndEveryone","manageReactions","exportChannelMessages","bypassSlowmode","pinMessages","seeDeletedMessages","moderateMembers","manageStickers"];var Z=class{id;options;toJSON(){let e=[];if(this.options)for(let[t,s]of Object.entries(this.options))e.push({name:t,description:s.description,type:this.mapType(s.type),required:s.required});return{name:this.name,description:this.description,options:e.length>0?e:void 0}}mapType(e){switch(e){case"string":return 3;case"integer":return 4;case"boolean":return 5;case"user":return 6;case"channel":return 7;case"role":return 8;default:return 3}}};export{m as APIError,J as ApplicationCommandManager,M as BadGatewayError,k as BadRequestError,Z as BotCommand,X as Client,y as EmbedBuilder,V as EventBus,S as ForbiddenError,A as GatewayTimeoutError,j as InlineBuilder,_ as Interaction,T as InternalServerError,Q as LogLevel,q as Logger,P as MermaidBuilder,R as Message,w as MessageBuilder,L as ModuleManager,x as NotFoundError,Ye as PERMISSION_KEYS,K as PollBuilder,O as RESTClient,$ as RateLimitError,H as SerchatError,U as ServiceUnavailableError,oe as SlashCommandOptionType,D as StickerManager,C as UnauthorizedError,B as WebSocketManager,N as WebhookManager,p as unwrap};
30
+ `;return this}mermaid(e){if(typeof e=="string")return this.codeBlock("mermaid",e);if(e instanceof k)return this.codeBlock("mermaid",e.build());{let t=new k;return e(t),this.codeBlock("mermaid",t.build())}}file(e){return this.content+=`[%file%](${e})
31
+ `,this}};var _=class{command;commandId;options;serverId;channelId;senderId;senderUsername;permissions;invocationId;client;constructor(e,t){this.client=e,this.command=t.command,this.commandId=t.commandId,this.options=t.options,this.serverId=t.serverId,this.channelId=t.channelId,this.senderId=t.senderId,this.senderUsername=t.senderUsername,this.permissions=t.senderPermissions||{},this.invocationId=t.invocationId}getOption(e){return this.options.find(t=>t.name===e)}getTypedOption(e,t){let s=this.getOption(e);return typeof s?.value===t?s?.value:void 0}getString(e){return this.getTypedOption(e,"string")}getInteger(e){return this.getTypedOption(e,"number")}getBoolean(e){return this.getTypedOption(e,"boolean")}getUser(e){return this.getString(e)}getChannel(e){return this.getString(e)}getRole(e){return this.getString(e)}hasPermission(e){return this.permissions.administrator?!0:!!this.permissions[e]}async reply(e){let t;return e instanceof y?t={embeds:[e.toJSON()]}:e instanceof E?t={content:e.build()}:typeof e=="string"?t={content:e}:(t={...e},t.embeds&&(t.embeds=t.embeds.map(s=>s instanceof y?s.toJSON():s))),t.interaction={command:this.command,options:this.options.map(s=>({name:s.name,value:s.value})),user:{id:this.senderId,username:this.senderUsername}},this.client.sendMessage(this.serverId,this.channelId,t)}};var J=class{ws=null;client;pendingRequests=new Map;constructor(e){this.client=e}reconnectAttempts=0;reconnectTimeout=null;connectionPromise=null;connectionResolve=null;connectionReject=null;heartbeatInterval=null;heartbeatTimeout=null;heartbeatRequestId=null;heartbeatIntervalMs=3e4;heartbeatTimeoutMs=1e4;async connect(){return this.connectionPromise?this.connectionPromise:(this.connectionPromise=new Promise((e,t)=>{this.connectionResolve=e,this.connectionReject=t,this._connect()}),this.connectionPromise)}_connect(){if(!this.client.getToken()){let s=new Error("Client is not logged in.");this.connectionReject&&(this.connectionReject(s),this.connectionPromise=null,this.connectionResolve=null,this.connectionReject=null);return}let t=(this.client.options.apiBaseUrl||"https://ser.chat/api/v1").replace(/^http/,"ws").replace(/\/api\/v1\/?$/,"/ws");this.client.logger.info(`Connecting to WebSocket at ${t}...`),this.ws&&(this.stopHeartbeat(),this.ws.removeAllListeners(),this.ws.close()),this.ws=new G(t),this.ws.on("open",()=>{let s=Y.randomUUID();this.ws.send(JSON.stringify({id:s,event:{type:"authenticate",payload:{token:this.client.getToken()}}}))}),this.ws.on("message",s=>{let r;try{r=JSON.parse(s.toString())}catch{return}if(r.event?.type==="authenticated"&&r.event.payload&&(this.client.user=r.event.payload.user,this.reconnectAttempts=0,this.startHeartbeat(),this.connectionResolve&&(this.connectionResolve(),this.connectionResolve=null,this.connectionReject=null),this.client.logger.info(`Authenticated as ${r.event.payload.user.username} (${r.event.payload.user.id})`),this.client.isReady?this.client.emit("reconnected"):(this.client.isReady=!0,this.client.emit("ready",r.event.payload.user))),r.event?.type==="pong"&&this.handleHeartbeatPong(r),r.meta?.replyTo&&this.pendingRequests.has(r.meta.replyTo)){let n=this.pendingRequests.get(r.meta.replyTo);if(this.pendingRequests.delete(r.meta.replyTo),clearTimeout(n.timeout),r.event?.type==="error"&&r.event.payload){let o=r.event.payload.details;n.reject(new Error(`WebSocket Error [${r.event.payload.code}]: ${o?.message}`))}else r.event?.payload&&n.resolve(r.event.payload)}let i=r.event;if(i)switch(i.type){case"message_server":this.client.emit("messageCreate",new w(this.client,i.payload));break;case"interaction_create_server":this.client.emit("interactionCreate",new _(this.client,i.payload));break;case"message_server_edited":this.client.emit("messageUpdate",i.payload);break;case"message_server_deleted":this.client.emit("messageDelete",i.payload);break;case"messages_server_bulk_deleted":this.client.emit("messageBulkDelete",i.payload);break;case"reaction_added":this.client.emit("messageReactionAdd",i.payload);break;case"reaction_removed":this.client.emit("messageReactionRemove",i.payload);break;case"poll_vote_updated_server":case"poll_vote_updated_dm":this.client.emit("pollVoteUpdate",i.payload);break;case"member_added":this.client.emit("serverMemberAdd",i.payload);break;case"member_removed":this.client.emit("serverMemberRemove",i.payload);break;case"member_updated":this.client.emit("serverMemberUpdate",i.payload);break;case"channel_created":this.client.emit("channelCreate",i.payload);break;case"channel_updated":this.client.emit("channelUpdate",i.payload);break;case"channel_deleted":this.client.emit("channelDelete",i.payload);break;case"channels_reordered":this.client.emit("channelsReordered",i.payload);break;case"category_created":this.client.emit("categoryCreate",i.payload);break;case"category_updated":this.client.emit("categoryUpdate",i.payload);break;case"category_deleted":this.client.emit("categoryDelete",i.payload);break;case"categories_reordered":this.client.emit("categoriesReordered",i.payload);break;case"channel_permissions_updated":this.client.emit("channelPermissionsUpdate",i.payload);break;case"category_permissions_updated":this.client.emit("categoryPermissionsUpdate",i.payload);break;case"server_updated":this.client.emit("serverUpdate",i.payload);break;case"server_deleted":this.client.emit("serverDelete",i.payload);break;case"server_icon_updated":this.client.emit("serverIconUpdate",i.payload);break;case"server_banner_updated":this.client.emit("serverBannerUpdate",i.payload);break;case"role_created":this.client.emit("roleCreate",i.payload);break;case"role_updated":this.client.emit("roleUpdate",i.payload);break;case"role_deleted":this.client.emit("roleDelete",i.payload);break;case"roles_reordered":this.client.emit("rolesReordered",i.payload);break;case"server_invite_created":this.client.emit("inviteCreate",i.payload);break;case"server_invite_deleted":this.client.emit("inviteDelete",i.payload);break;case"member_banned":this.client.emit("serverMemberBan",i.payload);break;case"member_unbanned":this.client.emit("serverMemberUnban",i.payload);break;case"ownership_transferred":this.client.emit("ownershipTransfer",i.payload);break;case"presence_sync":this.client.emit("presenceSync",i.payload);break;case"user_online":this.client.emit("userOnline",i.payload);break;case"user_offline":this.client.emit("userOffline",i.payload);break;case"user_updated":this.client.emit("userUpdate",i.payload);break;case"error":case"ping":case"pong":case"authenticated":case"server_joined":break}}),this.ws.on("error",s=>{this.client.logger.error(`WebSocket error: ${s.message}`),this.stopHeartbeat(),this.connectionReject&&(this.connectionReject(s),this.connectionPromise=null,this.connectionResolve=null,this.connectionReject=null)}),this.ws.on("close",(s,r)=>{this.stopHeartbeat(),this.client.logger.warn(`WebSocket connection closed. Code: ${s}, Reason: ${r?r.toString():"None"}`),this.client.emit("disconnect"),this.connectionReject&&(this.connectionReject(new Error(`WebSocket closed before authentication. Code: ${s}, Reason: ${r?r.toString():"None"}`)),this.connectionPromise=null,this.connectionResolve=null,this.connectionReject=null),this.scheduleReconnect()})}startHeartbeat(){this.stopHeartbeat(),this.heartbeatInterval=setInterval(()=>{this.sendHeartbeat()},this.heartbeatIntervalMs),this.heartbeatInterval.unref(),this.sendHeartbeat()}stopHeartbeat(){this.heartbeatInterval!==null&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null),this.heartbeatTimeout!==null&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=null),this.heartbeatRequestId=null}sendHeartbeat(){if(!this.ws||this.ws.readyState!==G.OPEN||this.heartbeatRequestId!==null)return;let e=Y.randomUUID();this.heartbeatRequestId=e,this.ws.send(JSON.stringify({id:e,event:{type:"ping",payload:{}}})),this.heartbeatTimeout=setTimeout(()=>{this.client.logger.warn("WebSocket heartbeat timed out; reconnecting..."),this.heartbeatTimeout=null,this.heartbeatRequestId=null,this.ws?.terminate()},this.heartbeatTimeoutMs),this.heartbeatTimeout.unref()}handleHeartbeatPong(e){this.heartbeatRequestId!==null&&e.meta?.replyTo===this.heartbeatRequestId&&(this.heartbeatRequestId=null,this.heartbeatTimeout!==null&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=null))}scheduleReconnect(){if(this.reconnectTimeout)return;let e=Math.min(1e3*Math.pow(2,this.reconnectAttempts),3e4);this.client.logger.info(`Scheduling reconnection in ${e}ms (attempt ${this.reconnectAttempts+1})`),this.reconnectAttempts++,this.reconnectTimeout=setTimeout(()=>{this.reconnectTimeout=null,this._connect()},e)}async joinServer(e){if(!this.ws||this.ws.readyState!==G.OPEN)throw new Error("WebSocket is not connected.");let t=Y.randomUUID();return new Promise((s,r)=>{let i=setTimeout(()=>{this.pendingRequests.delete(t),r(new Error("Request timeout"))},5e3);this.pendingRequests.set(t,{resolve:s,reject:r,timeout:i}),this.ws.send(JSON.stringify({id:t,event:{type:"join_server",payload:{serverId:e}}}))})}};var B=class{rest;registeredCommands=new Map;registeredCommandsById=new Map;constructor(e){this.rest=e}register(e){if(this.registeredCommands.has(e.name))throw new Error(`Command with name "${e.name}" is already registered.`);this.registeredCommands.set(e.name,e)}async handleInteraction(e){let t;e.commandId?t=this.registeredCommandsById.get(e.commandId):t=this.registeredCommands.get(e.command),t&&await t.execute(e)}getCommandsData(){return Array.from(this.registeredCommands.values()).map(e=>e.toJSON())}async sync(){await this.set(this.getCommandsData())}async set(e){let t=new Set;for(let i of e){if(t.has(i.name))throw new Error(`Duplicate command name found in set(): "${i.name}"`);t.add(i.name)}let s=await this.rest.put("/applications/@me/commands",{commands:e}),r=u(s);this.registeredCommandsById.clear();for(let i of r){let n=this.registeredCommands.get(i.name);n&&i.id&&(n.id=i.id,this.registeredCommandsById.set(i.id,n))}return r}};var D=class{rest;constructor(e){this.rest=e}async getStickers(){let e=await this.rest.get("/stickers");return u(e)}async getServerStickers(e){let t=await this.rest.get(`/servers/${e}/stickers`);return u(t)}async createSticker(e,t){let s=await this.rest.post(`/servers/${e}/stickers`,t);return u(s)}async deleteSticker(e,t){await this.rest.delete(`/servers/${e}/stickers/${t}`)}};var N=class{rest;constructor(e){this.rest=e}embedToJSON(e){return{type:e.type,color:e.color,title:e.title,url:e.url,description:e.description,timestamp:e.timestamp,author:e.author?{name:e.author.name,url:e.author.url,icon_url:e.author.icon_url}:void 0,footer:e.footer?{text:e.footer.text,icon_url:e.footer.icon_url}:void 0,thumbnail:e.thumbnail?{url:e.thumbnail.url,width:e.thumbnail.width,height:e.thumbnail.height}:void 0,image:e.image?{url:e.image.url,width:e.image.width,height:e.image.height}:void 0,video:e.video?{url:e.video.url,width:e.video.width,height:e.video.height}:void 0,provider:e.provider?{name:e.provider.name,url:e.provider.url}:void 0,fields:e.fields?.map(t=>({name:t.name,value:t.value,inline:t.inline}))}}async getWebhooks(e,t){let s=await this.rest.get(`/servers/${e}/channels/${t}/webhooks`);return u(s)}async createWebhook(e,t,s){let r={name:s.name,avatarUrl:s.avatarUrl},i=await this.rest.post(`/servers/${e}/channels/${t}/webhooks`,r);return u(i)}async deleteWebhook(e,t,s){await this.rest.delete(`/servers/${e}/channels/${t}/webhooks/${s}`)}async uploadWebhookAvatar(e,t,s,r){let i=new FormData;i.append("avatar",r);let n=await this.rest.post(`/servers/${e}/channels/${t}/webhooks/${s}/avatar`,i);return u(n)}async executeWebhook(e,t){let s={content:t.content,username:t.username,avatarUrl:t.avatarUrl,noEmbedsUrls:t.noEmbedsUrls?.slice(0,25),embeds:t.embeds?.map(i=>this.embedToJSON(i))},r=await this.rest.post(`/webhooks/${e}`,s);return u(r)}async editWebhookMessage(e,t,s){let r={content:s.content,username:s.username,avatarUrl:s.avatarUrl,noEmbedsUrls:s.noEmbedsUrls?.slice(0,25),embeds:s.embeds?.map(i=>this.embedToJSON(i))};await this.rest.patch(`/webhooks/${e}/messages/${t}`,r)}async deleteWebhookMessage(e,t){await this.rest.delete(`/webhooks/${e}/messages/${t}`)}};var V=class{listeners={};logger;errorEvent;subscriberListeners=new Map;constructor(e={}){this.logger=e.logger,this.errorEvent=e.errorEvent}register(e){if(!e||typeof e!="object")return;let t={},s=this.getMethods(e);for(let r of s)if(typeof r=="string"){let i=this.getEventNamesForCallback(r);for(let n of i){let o=e[r];if(typeof o=="function"){let h=o,g=(...f)=>{try{let d=h(...f);return d instanceof Promise&&d.catch(c=>{let b=c instanceof Error?c:new Error(String(c));this.handleListenerError(n,b)}),d}catch(d){let c=d instanceof Error?d:new Error(String(d));this.handleListenerError(n,c)}};this.on(n,g);let l=t[n];l||(l=new Set,t[n]=l),l.add(g)}}}Object.keys(t).length>0&&this.subscriberListeners.set(e,t)}unregister(e){let t=this.subscriberListeners.get(e);if(t){for(let s of Object.keys(t)){let r=t[s];if(r)for(let i of r)this.off(s,i)}this.subscriberListeners.delete(e)}}getEventNamesForCallback(e){if(!e.startsWith("on")||e.length<=2)return[];let t=e.slice(2),r=[t.charAt(0).toLowerCase()+t.slice(1)];return e==="onMessage"&&r.push("messageCreate"),e==="onMessageCreate"&&r.push("messageCreate"),e==="onInteraction"&&r.push("interactionCreate"),e==="onInteractionCreate"&&r.push("interactionCreate"),r}getMethods(e){let t=[],s=e;for(;s&&s!==Object.prototype;){let r=Object.getOwnPropertyNames(s);for(let i of r)if(i!=="constructor"&&typeof e[i]=="function"){let o=i;t.includes(o)||t.push(o)}s=Object.getPrototypeOf(s)}return t}on(e,t){let s=this.listeners[e];return s||(s=new Set,this.listeners[e]=s),s.add(t),this}once(e,t){let s=(...r)=>(this.off(e,s),t(...r));return this.on(e,s)}off(e,t){return this.listeners[e]?.delete(t),this}emit(e,...t){let s=this.listeners[e];if(!s||s.size===0)return!1;for(let r of s)try{let i=r(...t);i instanceof Promise&&i.catch(n=>{let o=n instanceof Error?n:new Error(String(n));this.handleListenerError(e,o)})}catch(i){let n=i instanceof Error?i:new Error(String(i));this.handleListenerError(e,n)}return!0}handleListenerError(e,t){this.logger?.error(`Event listener for "${String(e)}" failed: ${t.message}`),this.errorEvent&&e!==this.errorEvent&&this.emitError(t)}emitError(e){this.errorEvent&&this.emit(this.errorEvent,e)}};var L=class{client;registeredModules=new Map;constructor(e){this.client=e}async register(e){if(this.registeredModules.has(e.name))throw new Error(`Module with name "${e.name}" is already registered.`);e.register&&await e.register(this.client),this.client.events.register(e),this.registeredModules.set(e.name,e)}};var W=class{title="";options=[];multiSelect=!1;expiresAt;setTitle(e){return this.title=e,this}addOption(e,t){return this.options.push({text:e,emoji:t,emojiType:t?"unicode":void 0}),this}addCustomEmojiOption(e,t){return this.options.push({text:e,emojiId:t,emojiType:"custom"}),this}setMultiSelect(e){return this.multiSelect=e,this}setExpiresAt(e){return this.expiresAt=typeof e=="string"?e:e.toISOString(),this}toJSON(){return{title:this.title,options:this.options,multiSelect:this.multiSelect,expiresAt:this.expiresAt}}};var X=(n=>(n[n.DEBUG=0]="DEBUG",n[n.INFO=1]="INFO",n[n.WARN=2]="WARN",n[n.ERROR=3]="ERROR",n[n.CRITICAL=4]="CRITICAL",n[n.NONE=5]="NONE",n))(X||{}),K=class{level=1;constructor(e=1){this.level=e}getRegion(){let e=new Error().stack;if(!e)return"unknown";let s=e.split(`
32
+ `)[4];if(!s)return"unknown";let r=s.match(/(?:at\s+)?(?:.*\((.*)\)|at\s+(.*))/),n=(r?.[1]||r?.[2]||"unknown").split("/");return n[n.length-1]||"unknown"}format(e,t){let s=e.toLowerCase(),r={reset:"\x1B[0m",gray:"\x1B[90m",blue:"\x1B[34m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",magenta:"\x1B[35m",cyan:"\x1B[36m",bold:"\x1B[1m"},i={debug:r.blue,info:r.green,warning:r.yellow,error:r.red,critical:r.magenta+r.bold}[s]||r.reset,n=`${r.cyan}[sdk]${r.reset}`,o=`${r.gray}[${this.getRegion()}]${r.reset}`,h=`${i}[${s}]${r.reset}`,g=`${r.gray}[${new Date().toISOString()}]${r.reset}`;return`${n} ${o} ${h} ${g} - ${t}`}debug(e){this.level<=0&&console.debug(this.format("debug",e))}info(e){this.level<=1&&console.info(this.format("info",e))}warn(e){this.level<=2&&console.warn(this.format("warning",e))}error(e){this.level<=3&&console.error(this.format("error",e))}critical(e){this.level<=4&&console.error(this.format("critical",e))}};var Z=class extends ae{ws;commands;stickers;webhooks;events;modules;user=null;isReady=!1;options;logger;rest;token=null;clientCredentials=null;refreshTimer=null;refreshPromise=null;constructor(e={}){super(),this.options={apiBaseUrl:"https://ser.chat/api/v1",logLevel:1,...e},this.logger=new K(this.options.logLevel),this.rest=new O({baseURL:this.options.apiBaseUrl}),this.events=new V({logger:this.logger,errorEvent:"error"}),this.ws=new J(this),this.commands=new B(this.rest),this.stickers=new D(this.rest),this.webhooks=new N(this.rest),this.modules=new L(this),this.events.on("interactionCreate",t=>{this.commands.handleInteraction(t).catch(console.error)}),this.rest.interceptors.error.push(async t=>(!(t instanceof R)||this.clientCredentials===null||await this.refreshToken(),t))}on(e,t){return this.events.on(e,t),this}once(e,t){return this.events.once(e,t),this}off(e,t){return this.events.off(e,t),this}emit(e,...t){return this.events.emit(e,...t)}get application(){return{commands:this.commands}}getToken(){return this.token}getRest(){return this.rest}getApiOrigin(){try{return new URL(this.options.apiBaseUrl).origin}catch{return this.options.apiBaseUrl}}async login(e,t){this.logger.info("Logging in with token..."),this.token=e,this.rest.setDefaultHeader("Authorization",`Bearer ${e}`),this.scheduleTokenRefresh(e),await this.connectWS(),t&&await t()}async loginWithSecret(e,t){this.clientCredentials={clientId:e,clientSecret:t};let s=await this.fetchTokenWithSecret(e,t);return await this.login(s),s}async refreshToken(){if(this.clientCredentials===null)throw new Error("Cannot refresh token without client credentials.");return this.refreshPromise?this.refreshPromise:(this.refreshPromise=this.fetchTokenWithSecret(this.clientCredentials.clientId,this.clientCredentials.clientSecret).then(e=>(this.token=e,this.rest.setDefaultHeader("Authorization",`Bearer ${e}`),this.scheduleTokenRefresh(e),this.reconnectWS(),e)).finally(()=>{this.refreshPromise=null}),this.refreshPromise)}async fetchTokenWithSecret(e,t){let s=await this.rest.post("/bots/token",{client_id:e,client_secret:t});return u(s).token}scheduleTokenRefresh(e){if(this.refreshTimer!==null&&(clearTimeout(this.refreshTimer),this.refreshTimer=null),this.clientCredentials===null)return;let t=this.getJwtExpirationMs(e);if(t===null)return;let s=t-300*1e3,r=Math.max(s-Date.now(),0);this.refreshTimer=setTimeout(()=>{this.refreshToken().catch(i=>{let n=i instanceof Error?i.message:String(i);this.logger.error(`Failed to refresh bot token: ${n}`)})},r),this.refreshTimer.unref()}getJwtExpirationMs(e){let[,t]=e.split(".");if(!t)return null;try{let s=t.replace(/-/g,"+").replace(/_/g,"/"),r=JSON.parse(Buffer.from(s,"base64").toString("utf8"));return typeof r.exp=="number"?r.exp*1e3:null}catch{return null}}reconnectWS(){this.ws.ws&&this.ws.ws.close(4e3,"Refreshing authentication token")}async connectWS(){await this.ws.connect()}async sendMessage(e,t,s){if(!this.token)throw new Error("Client is not logged in.");let r;s instanceof y?r={embeds:[s.toJSON()]}:s instanceof E?r={content:s.build()}:s instanceof W?r={poll:s.toJSON()}:typeof s=="string"?r={content:s}:(r={...s},r.embeds&&(r.embeds=r.embeds.map(n=>n instanceof y?n.toJSON():n)),r.noEmbedsUrls&&(r.noEmbedsUrls=r.noEmbedsUrls.slice(0,25)),r.poll&&"toJSON"in r.poll&&(r.poll=r.poll.toJSON()));let i=await this.rest.post(`/servers/${e}/channels/${t}/messages`,r);return new w(this,u(i))}async votePoll(e,t,s,r){if(!this.token)throw new Error("Client is not logged in.");await this.rest.post(`/servers/${e}/channels/${t}/messages/${s}/poll/vote`,{id:r})}async getMessages(e,t,s=50){if(!this.token)throw new Error("Client is not logged in.");let r=await this.rest.get(`/servers/${e}/channels/${t}/messages`,{params:{limit:s}});return u(r).map(i=>new w(this,i))}async bulkDeleteMessages(e,t,s){if(!this.token)throw new Error("Client is not logged in.");let r=await this.rest.post(`/servers/${e}/channels/${t}/messages/bulk-delete`,{messageIds:s});return u(r).deletedCount}async reactToMessage(e,t,s,r){if(!this.token)throw new Error("Client is not logged in.");await this.rest.post(`/servers/${e}/channels/${t}/messages/${s}/reactions`,{emoji:r})}async deleteMessage(e,t,s){if(!this.token)throw new Error("Client is not logged in.");await this.rest.delete(`/servers/${e}/channels/${t}/messages/${s}`)}async banMember(e,t,s,r=0){if(!this.token)throw new Error("Client is not logged in.");await this.rest.post(`/servers/${e}/bans`,{userId:t,reason:s??null,deleteMessageDays:r})}async unbanMember(e,t,s){if(!this.token)throw new Error("Client is not logged in.");await this.rest.delete(`/servers/${e}/bans/${t}`,{data:{reason:s??null}})}async kickMember(e,t,s){if(!this.token)throw new Error("Client is not logged in.");await this.rest.delete(`/servers/${e}/members/${t}`,{data:{reason:s??null}})}async timeoutMember(e,t,s,r){if(!this.token)throw new Error("Client is not logged in.");await this.rest.post(`/servers/${e}/members/${t}/timeout`,{duration:s,reason:r??null})}async updateChannel(e,t,s){if(!this.token)throw new Error("Client is not logged in.");await this.rest.patch(`/servers/${e}/channels/${t}`,s)}async getServer(e){if(!this.token)throw new Error("Client is not logged in.");let t=await this.rest.get(`/servers/${e}`);return u(t)}async getChannelStats(e,t){if(!this.token)throw new Error("Client is not logged in.");let s=await this.rest.get(`/servers/${e}/channels/${t}/stats`);return u(s)}async getServerStats(e){if(!this.token)throw new Error("Client is not logged in.");let t=await this.rest.get(`/servers/${e}/stats`);return u(t)}async getRoles(e){if(!this.token)throw new Error("Client is not logged in.");let t=await this.rest.get(`/servers/${e}/roles`);return u(t)}async hasPermission(e,t,s){try{let r=await this.getServer(e);if(r&&(r.ownerId===t||r._id===t))return!0;let[i,n]=await Promise.all([this.rest.get(`/servers/${e}/members/${t}`),this.getRoles(e)]),o=u(i),h=o&&typeof o=="object"&&"roles"in o?o.roles:o&&typeof o=="object"&&"member"in o?o.member.roles:[];if(!Array.isArray(h))return!1;let g=n.find(c=>c.name==="@everyone"),l=new Set(h);g&&l.add(g.id||g._id);let f=n.filter(c=>l.has(c.id||c._id)).sort((c,b)=>c.position-b.position);for(let c of f){let b=typeof c.permissions=="string"?JSON.parse(c.permissions):c.permissions;if(b&&b.administrator===!0)return!0}let d=!1;for(let c of f){let b=typeof c.permissions=="string"?JSON.parse(c.permissions):c.permissions;b&&typeof b[s]=="boolean"&&(d=b[s])}return d}catch(r){this.logger.error(`Failed to check permission: ${r}`)}return!1}};var le=(o=>(o[o.SUB_COMMAND=1]="SUB_COMMAND",o[o.STRING=3]="STRING",o[o.INTEGER=4]="INTEGER",o[o.BOOLEAN=5]="BOOLEAN",o[o.USER=6]="USER",o[o.CHANNEL=7]="CHANNEL",o[o.ROLE=8]="ROLE",o))(le||{});var Ze=["viewChannels","sendMessages","addReactions","connect","manageMessages","deleteMessagesOfOthers","manageChannels","manageRoles","banMembers","kickMembers","manageInvites","manageServer","administrator","manageWebhooks","pingRolesAndEveryone","manageReactions","exportChannelMessages","bypassSlowmode","pinMessages","seeDeletedMessages","moderateMembers","manageStickers"];var ee=class{id;options;toJSON(){let e=[];if(this.options)for(let[t,s]of Object.entries(this.options))e.push({name:t,description:s.description,type:this.mapType(s.type),required:s.required});return{name:this.name,description:this.description,options:e.length>0?e:void 0}}mapType(e){switch(e){case"string":return 3;case"integer":return 4;case"boolean":return 5;case"user":return 6;case"channel":return 7;case"role":return 8;default:return 3}}};export{m as APIError,B as ApplicationCommandManager,M as BadGatewayError,C as BadRequestError,ee as BotCommand,Z as Client,y as EmbedBuilder,V as EventBus,S as ForbiddenError,A as GatewayTimeoutError,j as InlineBuilder,_ as Interaction,$ as InternalServerError,X as LogLevel,K as Logger,k as MermaidBuilder,w as Message,E as MessageBuilder,L as ModuleManager,x as NotFoundError,Ze as PERMISSION_KEYS,W as PollBuilder,O as RESTClient,T as RateLimitError,H as SerchatError,U as ServiceUnavailableError,le as SlashCommandOptionType,D as StickerManager,R as UnauthorizedError,J as WebSocketManager,N as WebhookManager,u as unwrap};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serchat.ts",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "TypeScript SDK for Serchat",
5
5
  "author": "Serchat",
6
6
  "license": "MIT",