serchat.ts 0.1.5 → 0.1.7

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;
@@ -469,6 +484,8 @@ export interface ISendMessageRequest {
469
484
  poll?: IPollInput | {
470
485
  toJSON(): IPollInput;
471
486
  };
487
+ /** When true, the response is only visible to the user who invoked the command. */
488
+ ephemeral?: boolean;
472
489
  }
473
490
  export interface IMessageWithEmbeds {
474
491
  embeds?: (IEmbed | {
@@ -835,8 +852,8 @@ export declare class EmbedBuilder {
835
852
  export declare class Message implements IMessageServer {
836
853
  /** Primary message identifier. Normalised from either `messageId` or `_id`. */
837
854
  messageId: string;
838
- /** Legacy MongoDB `_id` field, present on older messages. */
839
- _id?: string;
855
+ /** MongoDB `_id` field. */
856
+ _id: string;
840
857
  /** ID of the server this message belongs to. */
841
858
  serverId: string;
842
859
  /** ID of the channel this message was posted in. */
@@ -871,11 +888,13 @@ export declare class Message implements IMessageServer {
871
888
  /** Avatar URL override for webhook messages. */
872
889
  webhookAvatarUrl?: string;
873
890
  /** Rich embed objects attached to this message. */
874
- embeds?: IEmbed[];
891
+ embeds: IEmbed[];
875
892
  /** Structured file attachments on this message. */
876
- attachments?: IMessageAttachment[];
893
+ attachments: IMessageAttachment[];
894
+ /** Aggregated reaction data on this message. */
895
+ reactions: MessageReaction[];
877
896
  /** Interaction metadata if this message was sent in response to a slash command. */
878
- interaction?: {
897
+ interaction: {
879
898
  command: string;
880
899
  options: {
881
900
  name: string;
@@ -885,11 +904,11 @@ export declare class Message implements IMessageServer {
885
904
  id: string;
886
905
  username: string;
887
906
  };
888
- };
907
+ } | null;
889
908
  /** Poll attached to this message, if any. */
890
- poll?: IPoll;
909
+ poll: IPoll | null;
891
910
  /** Sticker attached to this message, if any. */
892
- stickerId?: string;
911
+ stickerId: string | null;
893
912
  /** Whether the message sender is a bot account. */
894
913
  senderIsBot: boolean;
895
914
  private client;
@@ -1197,8 +1216,16 @@ export declare class Interaction {
1197
1216
  getRole(name: string): string | undefined;
1198
1217
  /** Checks if the user has a specific permission. */
1199
1218
  hasPermission(permission: PermissionKey): boolean;
1200
- /** Sends a reply to this interaction. */
1219
+ /** Sends a reply to this interaction (visible to all channel members). */
1201
1220
  reply(content: string | ISendMessageRequest | EmbedBuilder | IMessageWithEmbeds | MessageBuilder): Promise<Message>;
1221
+ /**
1222
+ * Sends an ephemeral reply to this interaction.
1223
+ *
1224
+ * The response is delivered only to the user who invoked the command
1225
+ * via a WebSocket event. It is never saved to the database and
1226
+ * never broadcast to other channel members.
1227
+ */
1228
+ ephemeralReply(content: string | ISendMessageRequest | EmbedBuilder | IMessageWithEmbeds | MessageBuilder): Promise<void>;
1202
1229
  }
1203
1230
  /** Union of supported slash-command option value types. */
1204
1231
  export type CommandOptionType = "string" | "integer" | "boolean" | "user" | "channel" | "role";
@@ -1865,6 +1892,9 @@ export declare class Client extends EventEmitter {
1865
1892
  logger: Logger;
1866
1893
  private rest;
1867
1894
  private token;
1895
+ private clientCredentials;
1896
+ private refreshTimer;
1897
+ private refreshPromise;
1868
1898
  constructor(options?: ClientOptions);
1869
1899
  /** Accessor for the application command manager. */
1870
1900
  get application(): {
@@ -1880,10 +1910,26 @@ export declare class Client extends EventEmitter {
1880
1910
  login(token: string, callback?: () => Promise<void>): Promise<void>;
1881
1911
  /** Exchanges client ID/secret for a token and logs in. */
1882
1912
  loginWithSecret(clientId: string, clientSecret: string): Promise<string>;
1913
+ /** Re-exchanges stored client credentials for a fresh access token. */
1914
+ refreshToken(): Promise<string>;
1915
+ private fetchTokenWithSecret;
1916
+ private scheduleTokenRefresh;
1917
+ private getJwtExpirationMs;
1918
+ private reconnectWS;
1883
1919
  /** Connects to the WebSocket gateway. */
1884
1920
  connectWS(): Promise<void>;
1885
1921
  /** Sends a message to a channel. */
1886
1922
  sendMessage(serverId: string, channelId: string, content: string | ISendMessageRequest | EmbedBuilder | IMessageWithEmbeds | MessageBuilder | PollBuilder): Promise<Message>;
1923
+ /**
1924
+ * Sends an ephemeral response for a bot interaction.
1925
+ *
1926
+ * The message is delivered only to the invoking user via a WebSocket event.
1927
+ * It is never persisted to the database and never broadcast to other channel members.
1928
+ *
1929
+ * You should call this via {@link Interaction.ephemeralReply} rather than
1930
+ * using this method directly.
1931
+ */
1932
+ sendEphemeralInteractionResponse(serverId: string, channelId: string, senderId: string, payload: ISendMessageRequest, invocationId?: string): Promise<void>;
1887
1933
  /** Votes on a poll option. */
1888
1934
  votePoll(serverId: string, channelId: string, messageId: string, optionId: string): Promise<void>;
1889
1935
  /** Fetches recent messages from a channel. */
@@ -1940,6 +1986,15 @@ export type WsEvent = {
1940
1986
  } | {
1941
1987
  type: "interaction_create_server";
1942
1988
  payload: InteractionCreatePayload;
1989
+ } | {
1990
+ type: "interaction_response_server";
1991
+ payload: {
1992
+ serverId: string;
1993
+ channelId: string;
1994
+ text: string;
1995
+ invocationId?: string;
1996
+ ephemeral?: boolean;
1997
+ };
1943
1998
  } | {
1944
1999
  type: "message_server_edited";
1945
2000
  payload: MessageUpdatePayload;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
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"}},E=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[y,d]of Object.entries(l))d!==void 0?i[y]=d:delete i[y]};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 y=t.timeout??this.options.timeout,d=new AbortController;this._pending.add(d);let c;y&&(c=setTimeout(()=>{d.abort(new DOMException("Request timed out","TimeoutError"))},y));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 K;try{K=await p.json()}catch{throw new m(p.status,{error:"Invalid JSON in response"},p)}return this.options.transformResponse?this.options.transformResponse(K,p):K}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 E(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 f=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;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 f?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
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+`
4
4
  `;else{let t=new j;e(t),this.content+=t.build()+`
@@ -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 f?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 f?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)}async ephemeralReply(e){let t;e instanceof f?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 f?s.toJSON():s))),await this.client.sendEphemeralInteractionResponse(this.serverId,this.channelId,this.senderId,t,this.invocationId)}};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 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":case"interaction_response_server":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=(...y)=>{try{let d=h(...y);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||{}),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}`,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 q(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 E)||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 f?r={embeds:[s.toJSON()]}:s instanceof w?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 f?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,u(i))}async sendEphemeralInteractionResponse(e,t,s,r,i){if(!this.token)throw new Error("Client is not logged in.");let n=r.content??r.text??"";await this.rest.post("/interactions/respond",{serverId:e,channelId:t,senderId:s,text:n,embeds:r.embeds??[],invocationId:i??null,ephemeral:!0})}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 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 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 y=n.filter(c=>l.has(c.id||c._id)).sort((c,b)=>c.position-b.position);for(let c of y){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 y){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,f as EmbedBuilder,V as EventBus,S as ForbiddenError,A as GatewayTimeoutError,j as InlineBuilder,_ as Interaction,$ as InternalServerError,X as LogLevel,q as Logger,k as MermaidBuilder,R as Message,w 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,E 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.7",
4
4
  "description": "TypeScript SDK for Serchat",
5
5
  "author": "Serchat",
6
6
  "license": "MIT",