@borealise/api 2.0.0-alpha.9 → 2.1.0-alpha.2

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/README.md CHANGED
@@ -5,15 +5,13 @@ Official JavaScript/TypeScript API client for [Borealise](https://borealise.com)
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @borealise/api axios
8
+ npm install @borealise/api
9
9
  # or
10
- yarn add @borealise/api axios
10
+ yarn add @borealise/api
11
11
  # or
12
- pnpm add @borealise/api axios
12
+ pnpm add @borealise/api
13
13
  ```
14
14
 
15
- > `axios` is a peer dependency — you need to install it alongside this package.
16
-
17
15
  ---
18
16
 
19
17
  ## Quick Start
@@ -26,7 +24,7 @@ Create a client once, then use resources:
26
24
  import { createApiClient } from '@borealise/api'
27
25
 
28
26
  const client = createApiClient({
29
- baseURL: 'https://prod.borealise.com',
27
+ baseURL: 'https://prod.borealise.com/api',
30
28
  })
31
29
 
32
30
  // Login
@@ -45,7 +43,7 @@ If you need more control, create the API and resources separately:
45
43
  import { createApi, createAuthResource, createRoomResource } from '@borealise/api'
46
44
 
47
45
  const api = createApi({
48
- baseURL: 'https://prod.borealise.com',
46
+ baseURL: 'https://prod.borealise.com/api',
49
47
  timeout: 15000,
50
48
  logging: false,
51
49
  })
@@ -63,7 +61,7 @@ await auth.login({ login: 'you@example.com', password: 'secret' })
63
61
 
64
62
  ```ts
65
63
  createApiClient({
66
- baseURL: 'https://prod.borealise.com', // required
64
+ baseURL: 'https://prod.borealise.com/api', // required
67
65
  timeout: 15000, // optional, default: 30000ms
68
66
  logging: false, // optional, disable all console output
69
67
  headers: { 'X-Custom-Header': 'value' } // optional, custom headers
@@ -217,7 +215,7 @@ try {
217
215
  if (err instanceof ApiError) {
218
216
  console.log(err.message) // Human-readable message from backend
219
217
  console.log(err.status) // HTTP status code, e.g. 401
220
- console.log(err.code) // Axios error code, e.g. 'NETWORK_ERROR'
218
+ console.log(err.code) // Error code, e.g. 'NETWORK_ERROR', 'TIMEOUT_ERROR', 'HTTP_401'
221
219
  console.log(err.response) // Raw backend error response body
222
220
  }
223
221
  }
@@ -241,6 +239,12 @@ client.api.setAuthToken(null)
241
239
 
242
240
  The underlying API instance is accessible via `client.api`. Use it for token management and custom headers:
243
241
 
242
+ ## Breaking Changes in 2.1.0-alpha.1
243
+
244
+ - The `axiosInstance` getter was removed from `Api`.
245
+ - The HTTP transport is now handled internally with Ky.
246
+ - If you previously accessed raw Axios internals, migrate to `Api` public methods (`get`, `post`, `put`, `patch`, `delete`, `setAuthToken`, `setHeader`, `removeHeader`).
247
+
244
248
  ---
245
249
 
246
250
  ## Tree-Shaking
package/dist/index.d.mts CHANGED
@@ -1,9 +1,8 @@
1
- import { AxiosRequestConfig, AxiosInstance } from 'axios';
2
-
3
1
  interface ApiConfig {
4
2
  baseURL: string;
5
3
  timeout?: number;
6
4
  headers?: Record<string, string>;
5
+ withCredentials?: boolean;
7
6
  /** Set to false to suppress all log output. Defaults to true. */
8
7
  logging?: boolean;
9
8
  }
@@ -12,34 +11,35 @@ interface ApiResponse<T = unknown> {
12
11
  status: number;
13
12
  headers: Record<string, string>;
14
13
  }
14
+ type ApiQueryParams = URLSearchParams | Record<string, unknown>;
15
+ interface ApiRequestConfig {
16
+ headers?: Record<string, string>;
17
+ params?: ApiQueryParams;
18
+ timeout?: number;
19
+ credentials?: 'omit' | 'same-origin' | 'include';
20
+ }
15
21
  interface BackendErrorResponse {
16
22
  success: false;
17
23
  error: string;
18
24
  }
25
+ interface Api {
26
+ setAuthToken(token: string | null): void;
27
+ setHeader(key: string, value: string): void;
28
+ removeHeader(key: string): void;
29
+ get<T = unknown>(url: string, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
30
+ post<T = unknown>(url: string, data?: unknown, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
31
+ put<T = unknown>(url: string, data?: unknown, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
32
+ patch<T = unknown>(url: string, data?: unknown, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
33
+ delete<T = unknown>(url: string, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
34
+ }
35
+
19
36
  declare class ApiError extends Error {
20
37
  readonly status?: number;
21
38
  readonly code?: string;
22
39
  readonly response?: BackendErrorResponse;
23
40
  constructor(message: string, status?: number, code?: string, response?: BackendErrorResponse);
24
41
  }
25
- declare class Api {
26
- private readonly axios;
27
- private readonly logger;
28
- private readonly config;
29
- constructor(config: ApiConfig);
30
- private setupInterceptors;
31
- private parseError;
32
- setAuthToken(token: string | null): void;
33
- setHeader(key: string, value: string): void;
34
- removeHeader(key: string): void;
35
- get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
36
- post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
37
- put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
38
- patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
39
- delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
40
- private wrapResponse;
41
- get axiosInstance(): AxiosInstance;
42
- }
42
+
43
43
  declare const createApi: (config: ApiConfig) => Api;
44
44
 
45
45
  declare class Logger {
@@ -111,7 +111,7 @@ interface MeResponse {
111
111
  interface AuthResource {
112
112
  login(credentials: LoginCredentials): Promise<ApiResponse<AuthResponse>>;
113
113
  register(data: RegisterData): Promise<ApiResponse<AuthResponse>>;
114
- refresh(refreshToken: string): Promise<ApiResponse<RefreshResponse>>;
114
+ refresh(refreshToken?: string): Promise<ApiResponse<RefreshResponse>>;
115
115
  logout(): Promise<ApiResponse<{
116
116
  success: boolean;
117
117
  message: string;
@@ -128,6 +128,34 @@ declare const createAuthResource: (api: Api) => AuthResource;
128
128
 
129
129
  interface User extends AuthUser {
130
130
  }
131
+ /**
132
+ * Public user profile — never contains private fields (email, flags, etc.)
133
+ */
134
+ interface PublicUser {
135
+ id: number;
136
+ username: string;
137
+ displayName: string | null;
138
+ avatarId: string;
139
+ bio: string | null;
140
+ globalRole: string;
141
+ xp: number;
142
+ level: number;
143
+ subscriptionType?: string | null;
144
+ subscriptionMonths?: number | null;
145
+ currentRoomSlug?: string | null;
146
+ createdAt?: string;
147
+ friendsCount: number;
148
+ }
149
+ /**
150
+ * A friend entry as shown on a public profile.
151
+ */
152
+ interface PublicProfileFriend {
153
+ id: number;
154
+ username: string;
155
+ displayName: string | null;
156
+ avatarId: string;
157
+ level: number;
158
+ }
131
159
  interface UpdateProfileData {
132
160
  displayName?: string;
133
161
  bio?: string;
@@ -136,7 +164,8 @@ type GlobalRole = 'user' | 'moderator' | 'admin' | 'owner';
136
164
  interface UserResponse {
137
165
  success: boolean;
138
166
  data: {
139
- user: User;
167
+ user: PublicUser;
168
+ friends: PublicProfileFriend[];
140
169
  };
141
170
  }
142
171
  interface MyViolation {
@@ -187,6 +216,22 @@ interface Room {
187
216
  population: number;
188
217
  totalPlays: number;
189
218
  isFeatured: boolean;
219
+ verified: boolean;
220
+ currentDJ?: {
221
+ id: number;
222
+ username: string;
223
+ displayName: string | null;
224
+ avatarId: string;
225
+ } | null;
226
+ currentMedia?: {
227
+ id: number;
228
+ source: 'youtube' | 'soundcloud';
229
+ sourceId: string;
230
+ title: string;
231
+ artist: string | null;
232
+ thumbnail: string | null;
233
+ duration: number;
234
+ } | null;
190
235
  createdAt: string;
191
236
  updatedAt: string;
192
237
  }
@@ -484,6 +529,7 @@ interface DashboardActivityResponse {
484
529
  }
485
530
  interface RoomResource {
486
531
  list(): Promise<ApiResponse<RoomsResponse>>;
532
+ mine(limit?: number): Promise<ApiResponse<RoomsResponse>>;
487
533
  featured(): Promise<ApiResponse<FeaturedRoomsResponse>>;
488
534
  getBySlug(slug: string): Promise<ApiResponse<RoomResponse>>;
489
535
  create(data: CreateRoomData): Promise<ApiResponse<RoomResponse>>;
@@ -579,6 +625,7 @@ interface ChatMessage {
579
625
  user_id?: number;
580
626
  username?: string;
581
627
  display_name?: string | null;
628
+ avatar_id?: string | null;
582
629
  role?: RoomRole;
583
630
  global_role?: string | null;
584
631
  subscription_type?: string | null;
@@ -586,7 +633,11 @@ interface ChatMessage {
586
633
  content: string;
587
634
  timestamp: number;
588
635
  type?: 'user' | 'system';
636
+ edited_at?: number | null;
637
+ edited_by?: number | null;
589
638
  deleted?: boolean;
639
+ deleted_at?: number | null;
640
+ deleted_by?: number | null;
590
641
  }
591
642
  interface SendMessageData {
592
643
  content: string;
@@ -606,6 +657,7 @@ interface ChatMessageResponse {
606
657
  interface ChatResource {
607
658
  sendMessage(slug: string, data: SendMessageData): Promise<ApiResponse<ChatMessageResponse>>;
608
659
  getMessages(slug: string, before?: string, limit?: number): Promise<ApiResponse<ChatMessagesResponse>>;
660
+ editMessage(slug: string, messageId: string, data: SendMessageData): Promise<ApiResponse<ChatMessageResponse>>;
609
661
  deleteMessage(slug: string, messageId: string): Promise<ApiResponse<{
610
662
  success: boolean;
611
663
  data: null;
@@ -802,6 +854,42 @@ interface PortalResponse {
802
854
  url: string;
803
855
  };
804
856
  }
857
+ interface CreateGiftCheckoutResponse {
858
+ success: boolean;
859
+ data: {
860
+ checkoutUrl: string;
861
+ sessionId: string;
862
+ };
863
+ }
864
+ interface GiftHistoryEntry {
865
+ giftItemId: number;
866
+ purchaseId: number;
867
+ status: string;
868
+ startsAt: string;
869
+ endsAt: string;
870
+ createdAt: string;
871
+ isAnonymous: boolean;
872
+ recipientUsername: string | null;
873
+ purchaserUsername: string | null;
874
+ }
875
+ interface GiftsHistoryResponse {
876
+ success: boolean;
877
+ data: {
878
+ purchased: GiftHistoryEntry[];
879
+ received: GiftHistoryEntry[];
880
+ failedPurchases: Array<{
881
+ purchaseId: number;
882
+ recipientUsername: string;
883
+ quantity: number;
884
+ createdAt: string;
885
+ }>;
886
+ supporterBadge: {
887
+ tier: 'none' | 'bronze' | 'silver' | 'gold';
888
+ giftedCount: number;
889
+ nextTierAt: number | null;
890
+ };
891
+ };
892
+ }
805
893
  interface SubscriptionResource {
806
894
  getStatus(): Promise<ApiResponse<{
807
895
  success: boolean;
@@ -812,6 +900,14 @@ interface SubscriptionResource {
812
900
  success: boolean;
813
901
  }>>;
814
902
  createPortal(): Promise<ApiResponse<PortalResponse>>;
903
+ createGiftCheckout(recipientUsername: string, quantity: 1 | 5 | 10 | 20, isAnonymous?: boolean): Promise<ApiResponse<CreateGiftCheckoutResponse>>;
904
+ getGiftsHistory(): Promise<ApiResponse<GiftsHistoryResponse>>;
905
+ retryGiftAssignment(purchaseId: number, recipientUsername?: string): Promise<ApiResponse<{
906
+ success: boolean;
907
+ data: {
908
+ ok: true;
909
+ };
910
+ }>>;
815
911
  }
816
912
  declare const createSubscriptionResource: (api: Api) => SubscriptionResource;
817
913
 
@@ -823,6 +919,7 @@ interface FriendEntry {
823
919
  displayName: string | null;
824
920
  avatarId: string;
825
921
  level: number;
922
+ currentRoomSlug?: string | null;
826
923
  status: 'pending' | 'accepted' | 'blocked';
827
924
  isSender: boolean;
828
925
  }
@@ -977,4 +1074,4 @@ interface ApiClient {
977
1074
  }
978
1075
  declare const createApiClient: (config: ApiConfig) => ApiClient;
979
1076
 
980
- export { type AccountViolation, type AddMediaData, type AddViolationResponse, type AdminListUsersParams, type AdminResource, type AdminStatsResponse, type AdminStatsRoom, type AdminUserEntry, type AdminUsersResponse, Api, type ApiClient, type ApiConfig, ApiError, type ApiResponse, type AuditAction, type AuthResource, type AuthUser, type AvatarCatalogItem, type AvatarCatalogResponse, type AvatarUnlockType, type BackendErrorResponse, type BanResponse, type BoothDJ, type BoothMedia, type BoothResponse, type BoothState, type ChatMessage, type ChatMessageResponse, type ChatMessagesResponse, type ChatResource, type CreateIntentResponse, type CreateRoomData, type DashboardActivityItem, type DashboardActivityResponse, type DashboardActivityType, type EquipAvatarData, type FeaturedRoomsResponse, type FriendActionResponse, type FriendEntry, type FriendList, type FriendListResponse, type FriendResource, type FriendStatusResponse, type FriendshipStatus, type GlobalRole, type GrabResponse, type ImportPlaylistData, type ImportPlaylistResponse, type ImportResult, type JoinMuteInfo, type JoinRoomResponse, Logger, type MediaItem, type MediaItemResponse, type MediaSearchResult, type MediaSource, type ModerateUserData, type MuteResponse, type MyViolation, type MyViolationsResponse, type PaginationMeta, type PlayHistoryItem, type Playlist, type PlaylistResource, type PlaylistResponse, type PlaylistsResponse, type PortalResponse, type Room, type RoomAuditLog, type RoomBan, type RoomBansResponse, type RoomHistoryResponse, type RoomMember, type RoomMute, type RoomMutesResponse, type RoomResource, type RoomResponse, type RoomRole, type RoomStaffResponse, type RoomUserState, type RoomsResponse, type SendMessageData, type ShopResource, type ShuffleResponse, type SoundCloudSearchResponse, type SoundCloudTrackResponse, type SourceResource, type SubscriptionPlan, type SubscriptionResource, type SubscriptionStatus, type UpdateProfileData, type UpdateRoomData, type User, type UserResource, type UserResponse, type UserViolationsResponse, type VoteResponse, type WaitlistResponse, type WaitlistUser, type YouTubeSearchResponse, type YouTubeVideoResponse, createAdminResource, createApi, createApiClient, createAuthResource, createChatResource, createFriendResource, createPlaylistResource, createRoomResource, createShopResource, createSourceResource, createSubscriptionResource, createUserResource };
1077
+ export { type AccountViolation, type AddMediaData, type AddViolationResponse, type AdminListUsersParams, type AdminResource, type AdminStatsResponse, type AdminStatsRoom, type AdminUserEntry, type AdminUsersResponse, type Api, type ApiClient, type ApiConfig, ApiError, type ApiQueryParams, type ApiRequestConfig, type ApiResponse, type AuditAction, type AuthResource, type AuthUser, type AvatarCatalogItem, type AvatarCatalogResponse, type AvatarUnlockType, type BackendErrorResponse, type BanResponse, type BoothDJ, type BoothMedia, type BoothResponse, type BoothState, type ChatMessage, type ChatMessageResponse, type ChatMessagesResponse, type ChatResource, type CreateIntentResponse, type CreateRoomData, type DashboardActivityItem, type DashboardActivityResponse, type DashboardActivityType, type EquipAvatarData, type FeaturedRoomsResponse, type FriendActionResponse, type FriendEntry, type FriendList, type FriendListResponse, type FriendResource, type FriendStatusResponse, type FriendshipStatus, type GlobalRole, type GrabResponse, type ImportPlaylistData, type ImportPlaylistResponse, type ImportResult, type JoinMuteInfo, type JoinRoomResponse, Logger, type MediaItem, type MediaItemResponse, type MediaSearchResult, type MediaSource, type ModerateUserData, type MuteResponse, type MyViolation, type MyViolationsResponse, type PaginationMeta, type PlayHistoryItem, type Playlist, type PlaylistResource, type PlaylistResponse, type PlaylistsResponse, type PortalResponse, type PublicProfileFriend, type PublicUser, type Room, type RoomAuditLog, type RoomBan, type RoomBansResponse, type RoomHistoryResponse, type RoomMember, type RoomMute, type RoomMutesResponse, type RoomResource, type RoomResponse, type RoomRole, type RoomStaffResponse, type RoomUserState, type RoomsResponse, type SendMessageData, type ShopResource, type ShuffleResponse, type SoundCloudSearchResponse, type SoundCloudTrackResponse, type SourceResource, type SubscriptionPlan, type SubscriptionResource, type SubscriptionStatus, type UpdateProfileData, type UpdateRoomData, type User, type UserResource, type UserResponse, type UserViolationsResponse, type VoteResponse, type WaitlistResponse, type WaitlistUser, type YouTubeSearchResponse, type YouTubeVideoResponse, createAdminResource, createApi, createApiClient, createAuthResource, createChatResource, createFriendResource, createPlaylistResource, createRoomResource, createShopResource, createSourceResource, createSubscriptionResource, createUserResource };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import { AxiosRequestConfig, AxiosInstance } from 'axios';
2
-
3
1
  interface ApiConfig {
4
2
  baseURL: string;
5
3
  timeout?: number;
6
4
  headers?: Record<string, string>;
5
+ withCredentials?: boolean;
7
6
  /** Set to false to suppress all log output. Defaults to true. */
8
7
  logging?: boolean;
9
8
  }
@@ -12,34 +11,35 @@ interface ApiResponse<T = unknown> {
12
11
  status: number;
13
12
  headers: Record<string, string>;
14
13
  }
14
+ type ApiQueryParams = URLSearchParams | Record<string, unknown>;
15
+ interface ApiRequestConfig {
16
+ headers?: Record<string, string>;
17
+ params?: ApiQueryParams;
18
+ timeout?: number;
19
+ credentials?: 'omit' | 'same-origin' | 'include';
20
+ }
15
21
  interface BackendErrorResponse {
16
22
  success: false;
17
23
  error: string;
18
24
  }
25
+ interface Api {
26
+ setAuthToken(token: string | null): void;
27
+ setHeader(key: string, value: string): void;
28
+ removeHeader(key: string): void;
29
+ get<T = unknown>(url: string, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
30
+ post<T = unknown>(url: string, data?: unknown, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
31
+ put<T = unknown>(url: string, data?: unknown, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
32
+ patch<T = unknown>(url: string, data?: unknown, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
33
+ delete<T = unknown>(url: string, config?: ApiRequestConfig): Promise<ApiResponse<T>>;
34
+ }
35
+
19
36
  declare class ApiError extends Error {
20
37
  readonly status?: number;
21
38
  readonly code?: string;
22
39
  readonly response?: BackendErrorResponse;
23
40
  constructor(message: string, status?: number, code?: string, response?: BackendErrorResponse);
24
41
  }
25
- declare class Api {
26
- private readonly axios;
27
- private readonly logger;
28
- private readonly config;
29
- constructor(config: ApiConfig);
30
- private setupInterceptors;
31
- private parseError;
32
- setAuthToken(token: string | null): void;
33
- setHeader(key: string, value: string): void;
34
- removeHeader(key: string): void;
35
- get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
36
- post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
37
- put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
38
- patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
39
- delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>>;
40
- private wrapResponse;
41
- get axiosInstance(): AxiosInstance;
42
- }
42
+
43
43
  declare const createApi: (config: ApiConfig) => Api;
44
44
 
45
45
  declare class Logger {
@@ -111,7 +111,7 @@ interface MeResponse {
111
111
  interface AuthResource {
112
112
  login(credentials: LoginCredentials): Promise<ApiResponse<AuthResponse>>;
113
113
  register(data: RegisterData): Promise<ApiResponse<AuthResponse>>;
114
- refresh(refreshToken: string): Promise<ApiResponse<RefreshResponse>>;
114
+ refresh(refreshToken?: string): Promise<ApiResponse<RefreshResponse>>;
115
115
  logout(): Promise<ApiResponse<{
116
116
  success: boolean;
117
117
  message: string;
@@ -128,6 +128,34 @@ declare const createAuthResource: (api: Api) => AuthResource;
128
128
 
129
129
  interface User extends AuthUser {
130
130
  }
131
+ /**
132
+ * Public user profile — never contains private fields (email, flags, etc.)
133
+ */
134
+ interface PublicUser {
135
+ id: number;
136
+ username: string;
137
+ displayName: string | null;
138
+ avatarId: string;
139
+ bio: string | null;
140
+ globalRole: string;
141
+ xp: number;
142
+ level: number;
143
+ subscriptionType?: string | null;
144
+ subscriptionMonths?: number | null;
145
+ currentRoomSlug?: string | null;
146
+ createdAt?: string;
147
+ friendsCount: number;
148
+ }
149
+ /**
150
+ * A friend entry as shown on a public profile.
151
+ */
152
+ interface PublicProfileFriend {
153
+ id: number;
154
+ username: string;
155
+ displayName: string | null;
156
+ avatarId: string;
157
+ level: number;
158
+ }
131
159
  interface UpdateProfileData {
132
160
  displayName?: string;
133
161
  bio?: string;
@@ -136,7 +164,8 @@ type GlobalRole = 'user' | 'moderator' | 'admin' | 'owner';
136
164
  interface UserResponse {
137
165
  success: boolean;
138
166
  data: {
139
- user: User;
167
+ user: PublicUser;
168
+ friends: PublicProfileFriend[];
140
169
  };
141
170
  }
142
171
  interface MyViolation {
@@ -187,6 +216,22 @@ interface Room {
187
216
  population: number;
188
217
  totalPlays: number;
189
218
  isFeatured: boolean;
219
+ verified: boolean;
220
+ currentDJ?: {
221
+ id: number;
222
+ username: string;
223
+ displayName: string | null;
224
+ avatarId: string;
225
+ } | null;
226
+ currentMedia?: {
227
+ id: number;
228
+ source: 'youtube' | 'soundcloud';
229
+ sourceId: string;
230
+ title: string;
231
+ artist: string | null;
232
+ thumbnail: string | null;
233
+ duration: number;
234
+ } | null;
190
235
  createdAt: string;
191
236
  updatedAt: string;
192
237
  }
@@ -484,6 +529,7 @@ interface DashboardActivityResponse {
484
529
  }
485
530
  interface RoomResource {
486
531
  list(): Promise<ApiResponse<RoomsResponse>>;
532
+ mine(limit?: number): Promise<ApiResponse<RoomsResponse>>;
487
533
  featured(): Promise<ApiResponse<FeaturedRoomsResponse>>;
488
534
  getBySlug(slug: string): Promise<ApiResponse<RoomResponse>>;
489
535
  create(data: CreateRoomData): Promise<ApiResponse<RoomResponse>>;
@@ -579,6 +625,7 @@ interface ChatMessage {
579
625
  user_id?: number;
580
626
  username?: string;
581
627
  display_name?: string | null;
628
+ avatar_id?: string | null;
582
629
  role?: RoomRole;
583
630
  global_role?: string | null;
584
631
  subscription_type?: string | null;
@@ -586,7 +633,11 @@ interface ChatMessage {
586
633
  content: string;
587
634
  timestamp: number;
588
635
  type?: 'user' | 'system';
636
+ edited_at?: number | null;
637
+ edited_by?: number | null;
589
638
  deleted?: boolean;
639
+ deleted_at?: number | null;
640
+ deleted_by?: number | null;
590
641
  }
591
642
  interface SendMessageData {
592
643
  content: string;
@@ -606,6 +657,7 @@ interface ChatMessageResponse {
606
657
  interface ChatResource {
607
658
  sendMessage(slug: string, data: SendMessageData): Promise<ApiResponse<ChatMessageResponse>>;
608
659
  getMessages(slug: string, before?: string, limit?: number): Promise<ApiResponse<ChatMessagesResponse>>;
660
+ editMessage(slug: string, messageId: string, data: SendMessageData): Promise<ApiResponse<ChatMessageResponse>>;
609
661
  deleteMessage(slug: string, messageId: string): Promise<ApiResponse<{
610
662
  success: boolean;
611
663
  data: null;
@@ -802,6 +854,42 @@ interface PortalResponse {
802
854
  url: string;
803
855
  };
804
856
  }
857
+ interface CreateGiftCheckoutResponse {
858
+ success: boolean;
859
+ data: {
860
+ checkoutUrl: string;
861
+ sessionId: string;
862
+ };
863
+ }
864
+ interface GiftHistoryEntry {
865
+ giftItemId: number;
866
+ purchaseId: number;
867
+ status: string;
868
+ startsAt: string;
869
+ endsAt: string;
870
+ createdAt: string;
871
+ isAnonymous: boolean;
872
+ recipientUsername: string | null;
873
+ purchaserUsername: string | null;
874
+ }
875
+ interface GiftsHistoryResponse {
876
+ success: boolean;
877
+ data: {
878
+ purchased: GiftHistoryEntry[];
879
+ received: GiftHistoryEntry[];
880
+ failedPurchases: Array<{
881
+ purchaseId: number;
882
+ recipientUsername: string;
883
+ quantity: number;
884
+ createdAt: string;
885
+ }>;
886
+ supporterBadge: {
887
+ tier: 'none' | 'bronze' | 'silver' | 'gold';
888
+ giftedCount: number;
889
+ nextTierAt: number | null;
890
+ };
891
+ };
892
+ }
805
893
  interface SubscriptionResource {
806
894
  getStatus(): Promise<ApiResponse<{
807
895
  success: boolean;
@@ -812,6 +900,14 @@ interface SubscriptionResource {
812
900
  success: boolean;
813
901
  }>>;
814
902
  createPortal(): Promise<ApiResponse<PortalResponse>>;
903
+ createGiftCheckout(recipientUsername: string, quantity: 1 | 5 | 10 | 20, isAnonymous?: boolean): Promise<ApiResponse<CreateGiftCheckoutResponse>>;
904
+ getGiftsHistory(): Promise<ApiResponse<GiftsHistoryResponse>>;
905
+ retryGiftAssignment(purchaseId: number, recipientUsername?: string): Promise<ApiResponse<{
906
+ success: boolean;
907
+ data: {
908
+ ok: true;
909
+ };
910
+ }>>;
815
911
  }
816
912
  declare const createSubscriptionResource: (api: Api) => SubscriptionResource;
817
913
 
@@ -823,6 +919,7 @@ interface FriendEntry {
823
919
  displayName: string | null;
824
920
  avatarId: string;
825
921
  level: number;
922
+ currentRoomSlug?: string | null;
826
923
  status: 'pending' | 'accepted' | 'blocked';
827
924
  isSender: boolean;
828
925
  }
@@ -977,4 +1074,4 @@ interface ApiClient {
977
1074
  }
978
1075
  declare const createApiClient: (config: ApiConfig) => ApiClient;
979
1076
 
980
- export { type AccountViolation, type AddMediaData, type AddViolationResponse, type AdminListUsersParams, type AdminResource, type AdminStatsResponse, type AdminStatsRoom, type AdminUserEntry, type AdminUsersResponse, Api, type ApiClient, type ApiConfig, ApiError, type ApiResponse, type AuditAction, type AuthResource, type AuthUser, type AvatarCatalogItem, type AvatarCatalogResponse, type AvatarUnlockType, type BackendErrorResponse, type BanResponse, type BoothDJ, type BoothMedia, type BoothResponse, type BoothState, type ChatMessage, type ChatMessageResponse, type ChatMessagesResponse, type ChatResource, type CreateIntentResponse, type CreateRoomData, type DashboardActivityItem, type DashboardActivityResponse, type DashboardActivityType, type EquipAvatarData, type FeaturedRoomsResponse, type FriendActionResponse, type FriendEntry, type FriendList, type FriendListResponse, type FriendResource, type FriendStatusResponse, type FriendshipStatus, type GlobalRole, type GrabResponse, type ImportPlaylistData, type ImportPlaylistResponse, type ImportResult, type JoinMuteInfo, type JoinRoomResponse, Logger, type MediaItem, type MediaItemResponse, type MediaSearchResult, type MediaSource, type ModerateUserData, type MuteResponse, type MyViolation, type MyViolationsResponse, type PaginationMeta, type PlayHistoryItem, type Playlist, type PlaylistResource, type PlaylistResponse, type PlaylistsResponse, type PortalResponse, type Room, type RoomAuditLog, type RoomBan, type RoomBansResponse, type RoomHistoryResponse, type RoomMember, type RoomMute, type RoomMutesResponse, type RoomResource, type RoomResponse, type RoomRole, type RoomStaffResponse, type RoomUserState, type RoomsResponse, type SendMessageData, type ShopResource, type ShuffleResponse, type SoundCloudSearchResponse, type SoundCloudTrackResponse, type SourceResource, type SubscriptionPlan, type SubscriptionResource, type SubscriptionStatus, type UpdateProfileData, type UpdateRoomData, type User, type UserResource, type UserResponse, type UserViolationsResponse, type VoteResponse, type WaitlistResponse, type WaitlistUser, type YouTubeSearchResponse, type YouTubeVideoResponse, createAdminResource, createApi, createApiClient, createAuthResource, createChatResource, createFriendResource, createPlaylistResource, createRoomResource, createShopResource, createSourceResource, createSubscriptionResource, createUserResource };
1077
+ export { type AccountViolation, type AddMediaData, type AddViolationResponse, type AdminListUsersParams, type AdminResource, type AdminStatsResponse, type AdminStatsRoom, type AdminUserEntry, type AdminUsersResponse, type Api, type ApiClient, type ApiConfig, ApiError, type ApiQueryParams, type ApiRequestConfig, type ApiResponse, type AuditAction, type AuthResource, type AuthUser, type AvatarCatalogItem, type AvatarCatalogResponse, type AvatarUnlockType, type BackendErrorResponse, type BanResponse, type BoothDJ, type BoothMedia, type BoothResponse, type BoothState, type ChatMessage, type ChatMessageResponse, type ChatMessagesResponse, type ChatResource, type CreateIntentResponse, type CreateRoomData, type DashboardActivityItem, type DashboardActivityResponse, type DashboardActivityType, type EquipAvatarData, type FeaturedRoomsResponse, type FriendActionResponse, type FriendEntry, type FriendList, type FriendListResponse, type FriendResource, type FriendStatusResponse, type FriendshipStatus, type GlobalRole, type GrabResponse, type ImportPlaylistData, type ImportPlaylistResponse, type ImportResult, type JoinMuteInfo, type JoinRoomResponse, Logger, type MediaItem, type MediaItemResponse, type MediaSearchResult, type MediaSource, type ModerateUserData, type MuteResponse, type MyViolation, type MyViolationsResponse, type PaginationMeta, type PlayHistoryItem, type Playlist, type PlaylistResource, type PlaylistResponse, type PlaylistsResponse, type PortalResponse, type PublicProfileFriend, type PublicUser, type Room, type RoomAuditLog, type RoomBan, type RoomBansResponse, type RoomHistoryResponse, type RoomMember, type RoomMute, type RoomMutesResponse, type RoomResource, type RoomResponse, type RoomRole, type RoomStaffResponse, type RoomUserState, type RoomsResponse, type SendMessageData, type ShopResource, type ShuffleResponse, type SoundCloudSearchResponse, type SoundCloudTrackResponse, type SourceResource, type SubscriptionPlan, type SubscriptionResource, type SubscriptionStatus, type UpdateProfileData, type UpdateRoomData, type User, type UserResource, type UserResponse, type UserViolationsResponse, type VoteResponse, type WaitlistResponse, type WaitlistUser, type YouTubeSearchResponse, type YouTubeVideoResponse, createAdminResource, createApi, createApiClient, createAuthResource, createChatResource, createFriendResource, createPlaylistResource, createRoomResource, createShopResource, createSourceResource, createSubscriptionResource, createUserResource };
package/dist/index.js CHANGED
@@ -30,7 +30,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- Api: () => Api,
34
33
  ApiError: () => ApiError,
35
34
  Logger: () => Logger,
36
35
  createAdminResource: () => createAdminResource,
@@ -48,8 +47,54 @@ __export(index_exports, {
48
47
  });
49
48
  module.exports = __toCommonJS(index_exports);
50
49
 
51
- // src/Api.ts
52
- var import_axios = __toESM(require("axios"));
50
+ // src/api/errors.ts
51
+ var import_ky = require("ky");
52
+ var ApiError = class extends Error {
53
+ constructor(message, status, code, response) {
54
+ super(message);
55
+ this.name = "ApiError";
56
+ this.status = status;
57
+ this.code = code;
58
+ this.response = response;
59
+ }
60
+ };
61
+ var tryParseErrorResponse = async (response) => {
62
+ const contentType = response.headers.get("content-type") ?? "";
63
+ if (contentType.includes("application/json")) {
64
+ return await response.json();
65
+ }
66
+ const text = await response.text();
67
+ return text || void 0;
68
+ };
69
+ var parseApiError = async (error) => {
70
+ if (error instanceof import_ky.HTTPError) {
71
+ const responseData = await tryParseErrorResponse(error.response);
72
+ const isObjectResponse = typeof responseData === "object" && responseData !== null;
73
+ let message;
74
+ let backendResponse;
75
+ if (isObjectResponse && "error" in responseData && responseData.error) {
76
+ message = responseData.error;
77
+ backendResponse = responseData;
78
+ } else if (isObjectResponse && "message" in responseData && responseData.message) {
79
+ message = responseData.message;
80
+ } else if (typeof responseData === "string" && responseData) {
81
+ message = responseData;
82
+ } else {
83
+ message = error.message;
84
+ }
85
+ return new ApiError(message, error.response.status, `HTTP_${error.response.status}`, backendResponse);
86
+ }
87
+ if (error instanceof import_ky.TimeoutError) {
88
+ return new ApiError("Request timed out", void 0, "TIMEOUT_ERROR");
89
+ }
90
+ if (error instanceof Error) {
91
+ return new ApiError(error.message, void 0, "NETWORK_ERROR");
92
+ }
93
+ return new ApiError("Unknown request error", void 0, "UNKNOWN_ERROR");
94
+ };
95
+
96
+ // src/api/client.ts
97
+ var import_ky2 = __toESM(require("ky"));
53
98
 
54
99
  // src/Logger.ts
55
100
  var Logger = class _Logger {
@@ -99,132 +144,114 @@ var Logger = class _Logger {
99
144
  }
100
145
  };
101
146
 
102
- // src/Api.ts
103
- var ApiError = class extends Error {
104
- constructor(message, status, code, response) {
105
- super(message);
106
- this.name = "ApiError";
107
- this.status = status;
108
- this.code = code;
109
- this.response = response;
147
+ // src/api/client.ts
148
+ var resolveUrl = (baseURL, url) => new URL(url, baseURL).toString();
149
+ var parseQueryParams = (params) => {
150
+ if (!params) {
151
+ return void 0;
110
152
  }
111
- };
112
- var Api = class {
113
- constructor(config) {
114
- this.config = config;
115
- this.logger = new Logger("Api");
116
- if (config.logging === false) {
117
- this.logger.disable();
118
- }
119
- this.axios = import_axios.default.create({
120
- baseURL: config.baseURL,
121
- timeout: config.timeout ?? 3e4,
122
- headers: {
123
- "Content-Type": "application/json",
124
- ...config.headers
125
- }
126
- });
127
- this.setupInterceptors();
128
- this.logger.success(`initialized (baseURL: ${config.baseURL})`);
153
+ if (params instanceof URLSearchParams) {
154
+ return params;
129
155
  }
130
- setupInterceptors() {
131
- this.axios.interceptors.request.use(
132
- (config) => {
133
- this.logger.debug(`\u2192 ${config.method?.toUpperCase()} ${config.url}`);
134
- return config;
135
- },
136
- (error) => {
137
- this.logger.error("Request error", error);
138
- return Promise.reject(error);
139
- }
140
- );
141
- this.axios.interceptors.response.use(
142
- (response) => {
143
- this.logger.debug(`\u2190 ${response.status} ${response.config.url}`);
144
- return response;
145
- },
146
- (error) => {
147
- const apiError = this.parseError(error);
148
- const status = apiError.status ?? apiError.code ?? "ERR";
149
- this.logger.error(`\u2190 ${status} ${error.config?.url}: ${apiError.message}`);
150
- return Promise.reject(apiError);
151
- }
152
- );
153
- }
154
- parseError(error) {
155
- if (error.response) {
156
- const responseData = error.response.data;
157
- let message;
158
- let backendResponse;
159
- if (responseData && "error" in responseData && responseData.error) {
160
- message = responseData.error;
161
- backendResponse = responseData;
162
- } else if (responseData && "message" in responseData && responseData.message) {
163
- message = responseData.message;
164
- } else {
165
- message = error.message;
166
- }
167
- return new ApiError(message, error.response.status, error.code, backendResponse);
168
- }
169
- if (error.request) {
170
- return new ApiError("No response received from server", void 0, "NETWORK_ERROR");
156
+ const searchParams = new URLSearchParams();
157
+ for (const [key, value] of Object.entries(params)) {
158
+ if (value === void 0 || value === null) {
159
+ continue;
171
160
  }
172
- return new ApiError(error.message, void 0, error.code);
173
- }
174
- setAuthToken(token) {
175
- if (token) {
176
- this.axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
177
- this.logger.debug("Auth token set");
178
- } else {
179
- delete this.axios.defaults.headers.common["Authorization"];
180
- this.logger.debug("Auth token cleared");
181
- }
182
- }
183
- setHeader(key, value) {
184
- this.axios.defaults.headers.common[key] = value;
161
+ searchParams.set(key, String(value));
185
162
  }
186
- removeHeader(key) {
187
- delete this.axios.defaults.headers.common[key];
188
- }
189
- async get(url, config) {
190
- const response = await this.axios.get(url, config);
191
- return this.wrapResponse(response);
192
- }
193
- async post(url, data, config) {
194
- const response = await this.axios.post(url, data, config);
195
- return this.wrapResponse(response);
196
- }
197
- async put(url, data, config) {
198
- const response = await this.axios.put(url, data, config);
199
- return this.wrapResponse(response);
200
- }
201
- async patch(url, data, config) {
202
- const response = await this.axios.patch(url, data, config);
203
- return this.wrapResponse(response);
204
- }
205
- async delete(url, config) {
206
- const response = await this.axios.delete(url, config);
207
- return this.wrapResponse(response);
208
- }
209
- wrapResponse(response) {
210
- return {
211
- data: response.data,
212
- status: response.status,
213
- headers: response.headers
214
- };
163
+ return searchParams;
164
+ };
165
+ var wrapResponse = async (response) => {
166
+ const contentType = response.headers.get("content-type") ?? "";
167
+ let data;
168
+ if (response.status === 204) {
169
+ data = void 0;
170
+ } else if (contentType.includes("application/json")) {
171
+ data = await response.json();
172
+ } else {
173
+ data = await response.text();
215
174
  }
216
- get axiosInstance() {
217
- return this.axios;
175
+ return {
176
+ data,
177
+ status: response.status,
178
+ headers: Object.fromEntries(response.headers.entries())
179
+ };
180
+ };
181
+ var buildOptions = (defaultHeaders, config) => ({
182
+ headers: {
183
+ ...defaultHeaders,
184
+ ...config?.headers
185
+ },
186
+ searchParams: parseQueryParams(config?.params),
187
+ timeout: config?.timeout,
188
+ credentials: config?.credentials
189
+ });
190
+ var createApi = (config) => {
191
+ const logger = new Logger("Api");
192
+ if (config.logging === false) {
193
+ logger.disable();
218
194
  }
195
+ const defaultHeaders = {
196
+ "Content-Type": "application/json",
197
+ ...config.headers
198
+ };
199
+ const client = import_ky2.default.create({
200
+ timeout: config.timeout ?? 3e4,
201
+ credentials: config.withCredentials ? "include" : "same-origin",
202
+ retry: 0,
203
+ throwHttpErrors: true
204
+ });
205
+ const request = async (method, url, data, requestConfig) => {
206
+ logger.debug(`\u2192 ${method.toUpperCase()} ${url}`);
207
+ try {
208
+ const options = buildOptions(defaultHeaders, requestConfig);
209
+ if (data !== void 0) {
210
+ options.json = data;
211
+ }
212
+ const response = await client(resolveUrl(config.baseURL, url), {
213
+ ...options,
214
+ method
215
+ });
216
+ logger.debug(`\u2190 ${response.status} ${url}`);
217
+ return wrapResponse(response);
218
+ } catch (error) {
219
+ const apiError = await parseApiError(error);
220
+ const status = apiError.status ?? apiError.code ?? "ERR";
221
+ logger.error(`\u2190 ${status} ${url}: ${apiError.message}`);
222
+ throw apiError;
223
+ }
224
+ };
225
+ return {
226
+ setAuthToken: (token) => {
227
+ if (token) {
228
+ defaultHeaders["Authorization"] = `Bearer ${token}`;
229
+ logger.debug("Auth token set");
230
+ } else {
231
+ delete defaultHeaders["Authorization"];
232
+ logger.debug("Auth token cleared");
233
+ }
234
+ },
235
+ setHeader: (key, value) => {
236
+ defaultHeaders[key] = value;
237
+ },
238
+ removeHeader: (key) => {
239
+ delete defaultHeaders[key];
240
+ },
241
+ get: (url, requestConfig) => request("get", url, void 0, requestConfig),
242
+ post: (url, data, requestConfig) => request("post", url, data, requestConfig),
243
+ put: (url, data, requestConfig) => request("put", url, data, requestConfig),
244
+ patch: (url, data, requestConfig) => request("patch", url, data, requestConfig),
245
+ delete: (url, requestConfig) => request("delete", url, void 0, requestConfig)
246
+ };
219
247
  };
220
- var createApi = (config) => new Api(config);
221
248
 
222
249
  // src/resources/auth.ts
223
250
  var endpoint = "/auth";
224
251
  var createAuthResource = (api) => ({
225
252
  login: (credentials) => api.post(`${endpoint}/login`, credentials),
226
253
  register: (data) => api.post(`${endpoint}/register`, data),
227
- refresh: (refreshToken) => api.post(`${endpoint}/refresh`, { refreshToken }),
254
+ refresh: (refreshToken) => api.post(`${endpoint}/refresh`, refreshToken ? { refreshToken } : {}),
228
255
  logout: () => api.post(`${endpoint}/logout`),
229
256
  me: () => api.get(`${endpoint}/me`),
230
257
  forgotPassword: (email) => api.post(`${endpoint}/forgot-password`, { email }),
@@ -247,6 +274,7 @@ var createUserResource = (api) => ({
247
274
  var endpoint3 = "/rooms";
248
275
  var createRoomResource = (api) => ({
249
276
  list: () => api.get(endpoint3),
277
+ mine: (limit = 20) => api.get(`${endpoint3}/mine`, { params: { limit } }),
250
278
  featured: () => api.get(`${endpoint3}/featured`),
251
279
  getBySlug: (slug) => api.get(`${endpoint3}/${slug}`),
252
280
  create: (data) => api.post(endpoint3, data),
@@ -299,6 +327,7 @@ var createChatResource = (api) => ({
299
327
  }
300
328
  return api.get(`${endpoint4}/${slug}/chat`, { params });
301
329
  },
330
+ editMessage: (slug, messageId, data) => api.patch(`${endpoint4}/${slug}/chat/${messageId}`, data),
302
331
  deleteMessage: (slug, messageId) => api.delete(`${endpoint4}/${slug}/chat/${messageId}`)
303
332
  });
304
333
 
@@ -365,7 +394,17 @@ var createSubscriptionResource = (api) => ({
365
394
  getStatus: () => api.get(`${endpoint8}/status`),
366
395
  createIntent: (plan) => api.post(`${endpoint8}/create-intent`, { plan }),
367
396
  cancelIntent: (subscriptionId) => api.post(`${endpoint8}/cancel-intent`, { subscriptionId }),
368
- createPortal: () => api.post(`${endpoint8}/portal`)
397
+ createPortal: () => api.post(`${endpoint8}/portal`),
398
+ createGiftCheckout: (recipientUsername, quantity, isAnonymous = false) => api.post(`${endpoint8}/create-gift-checkout`, {
399
+ recipientUsername,
400
+ quantity,
401
+ isAnonymous
402
+ }),
403
+ getGiftsHistory: () => api.get(`${endpoint8}/gifts-history`),
404
+ retryGiftAssignment: (purchaseId, recipientUsername) => api.post(`${endpoint8}/retry-gift-assignment`, {
405
+ purchaseId,
406
+ recipientUsername
407
+ })
369
408
  });
370
409
 
371
410
  // src/resources/friend.ts
@@ -425,7 +464,6 @@ var createApiClient = (config) => {
425
464
  };
426
465
  // Annotate the CommonJS export names for ESM import in node:
427
466
  0 && (module.exports = {
428
- Api,
429
467
  ApiError,
430
468
  Logger,
431
469
  createAdminResource,
package/dist/index.mjs CHANGED
@@ -1,5 +1,51 @@
1
- // src/Api.ts
2
- import axios from "axios";
1
+ // src/api/errors.ts
2
+ import { HTTPError, TimeoutError } from "ky";
3
+ var ApiError = class extends Error {
4
+ constructor(message, status, code, response) {
5
+ super(message);
6
+ this.name = "ApiError";
7
+ this.status = status;
8
+ this.code = code;
9
+ this.response = response;
10
+ }
11
+ };
12
+ var tryParseErrorResponse = async (response) => {
13
+ const contentType = response.headers.get("content-type") ?? "";
14
+ if (contentType.includes("application/json")) {
15
+ return await response.json();
16
+ }
17
+ const text = await response.text();
18
+ return text || void 0;
19
+ };
20
+ var parseApiError = async (error) => {
21
+ if (error instanceof HTTPError) {
22
+ const responseData = await tryParseErrorResponse(error.response);
23
+ const isObjectResponse = typeof responseData === "object" && responseData !== null;
24
+ let message;
25
+ let backendResponse;
26
+ if (isObjectResponse && "error" in responseData && responseData.error) {
27
+ message = responseData.error;
28
+ backendResponse = responseData;
29
+ } else if (isObjectResponse && "message" in responseData && responseData.message) {
30
+ message = responseData.message;
31
+ } else if (typeof responseData === "string" && responseData) {
32
+ message = responseData;
33
+ } else {
34
+ message = error.message;
35
+ }
36
+ return new ApiError(message, error.response.status, `HTTP_${error.response.status}`, backendResponse);
37
+ }
38
+ if (error instanceof TimeoutError) {
39
+ return new ApiError("Request timed out", void 0, "TIMEOUT_ERROR");
40
+ }
41
+ if (error instanceof Error) {
42
+ return new ApiError(error.message, void 0, "NETWORK_ERROR");
43
+ }
44
+ return new ApiError("Unknown request error", void 0, "UNKNOWN_ERROR");
45
+ };
46
+
47
+ // src/api/client.ts
48
+ import ky from "ky";
3
49
 
4
50
  // src/Logger.ts
5
51
  var Logger = class _Logger {
@@ -49,132 +95,114 @@ var Logger = class _Logger {
49
95
  }
50
96
  };
51
97
 
52
- // src/Api.ts
53
- var ApiError = class extends Error {
54
- constructor(message, status, code, response) {
55
- super(message);
56
- this.name = "ApiError";
57
- this.status = status;
58
- this.code = code;
59
- this.response = response;
98
+ // src/api/client.ts
99
+ var resolveUrl = (baseURL, url) => new URL(url, baseURL).toString();
100
+ var parseQueryParams = (params) => {
101
+ if (!params) {
102
+ return void 0;
60
103
  }
61
- };
62
- var Api = class {
63
- constructor(config) {
64
- this.config = config;
65
- this.logger = new Logger("Api");
66
- if (config.logging === false) {
67
- this.logger.disable();
68
- }
69
- this.axios = axios.create({
70
- baseURL: config.baseURL,
71
- timeout: config.timeout ?? 3e4,
72
- headers: {
73
- "Content-Type": "application/json",
74
- ...config.headers
75
- }
76
- });
77
- this.setupInterceptors();
78
- this.logger.success(`initialized (baseURL: ${config.baseURL})`);
104
+ if (params instanceof URLSearchParams) {
105
+ return params;
79
106
  }
80
- setupInterceptors() {
81
- this.axios.interceptors.request.use(
82
- (config) => {
83
- this.logger.debug(`\u2192 ${config.method?.toUpperCase()} ${config.url}`);
84
- return config;
85
- },
86
- (error) => {
87
- this.logger.error("Request error", error);
88
- return Promise.reject(error);
89
- }
90
- );
91
- this.axios.interceptors.response.use(
92
- (response) => {
93
- this.logger.debug(`\u2190 ${response.status} ${response.config.url}`);
94
- return response;
95
- },
96
- (error) => {
97
- const apiError = this.parseError(error);
98
- const status = apiError.status ?? apiError.code ?? "ERR";
99
- this.logger.error(`\u2190 ${status} ${error.config?.url}: ${apiError.message}`);
100
- return Promise.reject(apiError);
101
- }
102
- );
103
- }
104
- parseError(error) {
105
- if (error.response) {
106
- const responseData = error.response.data;
107
- let message;
108
- let backendResponse;
109
- if (responseData && "error" in responseData && responseData.error) {
110
- message = responseData.error;
111
- backendResponse = responseData;
112
- } else if (responseData && "message" in responseData && responseData.message) {
113
- message = responseData.message;
114
- } else {
115
- message = error.message;
116
- }
117
- return new ApiError(message, error.response.status, error.code, backendResponse);
118
- }
119
- if (error.request) {
120
- return new ApiError("No response received from server", void 0, "NETWORK_ERROR");
107
+ const searchParams = new URLSearchParams();
108
+ for (const [key, value] of Object.entries(params)) {
109
+ if (value === void 0 || value === null) {
110
+ continue;
121
111
  }
122
- return new ApiError(error.message, void 0, error.code);
123
- }
124
- setAuthToken(token) {
125
- if (token) {
126
- this.axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
127
- this.logger.debug("Auth token set");
128
- } else {
129
- delete this.axios.defaults.headers.common["Authorization"];
130
- this.logger.debug("Auth token cleared");
131
- }
132
- }
133
- setHeader(key, value) {
134
- this.axios.defaults.headers.common[key] = value;
112
+ searchParams.set(key, String(value));
135
113
  }
136
- removeHeader(key) {
137
- delete this.axios.defaults.headers.common[key];
138
- }
139
- async get(url, config) {
140
- const response = await this.axios.get(url, config);
141
- return this.wrapResponse(response);
142
- }
143
- async post(url, data, config) {
144
- const response = await this.axios.post(url, data, config);
145
- return this.wrapResponse(response);
146
- }
147
- async put(url, data, config) {
148
- const response = await this.axios.put(url, data, config);
149
- return this.wrapResponse(response);
150
- }
151
- async patch(url, data, config) {
152
- const response = await this.axios.patch(url, data, config);
153
- return this.wrapResponse(response);
154
- }
155
- async delete(url, config) {
156
- const response = await this.axios.delete(url, config);
157
- return this.wrapResponse(response);
158
- }
159
- wrapResponse(response) {
160
- return {
161
- data: response.data,
162
- status: response.status,
163
- headers: response.headers
164
- };
114
+ return searchParams;
115
+ };
116
+ var wrapResponse = async (response) => {
117
+ const contentType = response.headers.get("content-type") ?? "";
118
+ let data;
119
+ if (response.status === 204) {
120
+ data = void 0;
121
+ } else if (contentType.includes("application/json")) {
122
+ data = await response.json();
123
+ } else {
124
+ data = await response.text();
165
125
  }
166
- get axiosInstance() {
167
- return this.axios;
126
+ return {
127
+ data,
128
+ status: response.status,
129
+ headers: Object.fromEntries(response.headers.entries())
130
+ };
131
+ };
132
+ var buildOptions = (defaultHeaders, config) => ({
133
+ headers: {
134
+ ...defaultHeaders,
135
+ ...config?.headers
136
+ },
137
+ searchParams: parseQueryParams(config?.params),
138
+ timeout: config?.timeout,
139
+ credentials: config?.credentials
140
+ });
141
+ var createApi = (config) => {
142
+ const logger = new Logger("Api");
143
+ if (config.logging === false) {
144
+ logger.disable();
168
145
  }
146
+ const defaultHeaders = {
147
+ "Content-Type": "application/json",
148
+ ...config.headers
149
+ };
150
+ const client = ky.create({
151
+ timeout: config.timeout ?? 3e4,
152
+ credentials: config.withCredentials ? "include" : "same-origin",
153
+ retry: 0,
154
+ throwHttpErrors: true
155
+ });
156
+ const request = async (method, url, data, requestConfig) => {
157
+ logger.debug(`\u2192 ${method.toUpperCase()} ${url}`);
158
+ try {
159
+ const options = buildOptions(defaultHeaders, requestConfig);
160
+ if (data !== void 0) {
161
+ options.json = data;
162
+ }
163
+ const response = await client(resolveUrl(config.baseURL, url), {
164
+ ...options,
165
+ method
166
+ });
167
+ logger.debug(`\u2190 ${response.status} ${url}`);
168
+ return wrapResponse(response);
169
+ } catch (error) {
170
+ const apiError = await parseApiError(error);
171
+ const status = apiError.status ?? apiError.code ?? "ERR";
172
+ logger.error(`\u2190 ${status} ${url}: ${apiError.message}`);
173
+ throw apiError;
174
+ }
175
+ };
176
+ return {
177
+ setAuthToken: (token) => {
178
+ if (token) {
179
+ defaultHeaders["Authorization"] = `Bearer ${token}`;
180
+ logger.debug("Auth token set");
181
+ } else {
182
+ delete defaultHeaders["Authorization"];
183
+ logger.debug("Auth token cleared");
184
+ }
185
+ },
186
+ setHeader: (key, value) => {
187
+ defaultHeaders[key] = value;
188
+ },
189
+ removeHeader: (key) => {
190
+ delete defaultHeaders[key];
191
+ },
192
+ get: (url, requestConfig) => request("get", url, void 0, requestConfig),
193
+ post: (url, data, requestConfig) => request("post", url, data, requestConfig),
194
+ put: (url, data, requestConfig) => request("put", url, data, requestConfig),
195
+ patch: (url, data, requestConfig) => request("patch", url, data, requestConfig),
196
+ delete: (url, requestConfig) => request("delete", url, void 0, requestConfig)
197
+ };
169
198
  };
170
- var createApi = (config) => new Api(config);
171
199
 
172
200
  // src/resources/auth.ts
173
201
  var endpoint = "/auth";
174
202
  var createAuthResource = (api) => ({
175
203
  login: (credentials) => api.post(`${endpoint}/login`, credentials),
176
204
  register: (data) => api.post(`${endpoint}/register`, data),
177
- refresh: (refreshToken) => api.post(`${endpoint}/refresh`, { refreshToken }),
205
+ refresh: (refreshToken) => api.post(`${endpoint}/refresh`, refreshToken ? { refreshToken } : {}),
178
206
  logout: () => api.post(`${endpoint}/logout`),
179
207
  me: () => api.get(`${endpoint}/me`),
180
208
  forgotPassword: (email) => api.post(`${endpoint}/forgot-password`, { email }),
@@ -197,6 +225,7 @@ var createUserResource = (api) => ({
197
225
  var endpoint3 = "/rooms";
198
226
  var createRoomResource = (api) => ({
199
227
  list: () => api.get(endpoint3),
228
+ mine: (limit = 20) => api.get(`${endpoint3}/mine`, { params: { limit } }),
200
229
  featured: () => api.get(`${endpoint3}/featured`),
201
230
  getBySlug: (slug) => api.get(`${endpoint3}/${slug}`),
202
231
  create: (data) => api.post(endpoint3, data),
@@ -249,6 +278,7 @@ var createChatResource = (api) => ({
249
278
  }
250
279
  return api.get(`${endpoint4}/${slug}/chat`, { params });
251
280
  },
281
+ editMessage: (slug, messageId, data) => api.patch(`${endpoint4}/${slug}/chat/${messageId}`, data),
252
282
  deleteMessage: (slug, messageId) => api.delete(`${endpoint4}/${slug}/chat/${messageId}`)
253
283
  });
254
284
 
@@ -315,7 +345,17 @@ var createSubscriptionResource = (api) => ({
315
345
  getStatus: () => api.get(`${endpoint8}/status`),
316
346
  createIntent: (plan) => api.post(`${endpoint8}/create-intent`, { plan }),
317
347
  cancelIntent: (subscriptionId) => api.post(`${endpoint8}/cancel-intent`, { subscriptionId }),
318
- createPortal: () => api.post(`${endpoint8}/portal`)
348
+ createPortal: () => api.post(`${endpoint8}/portal`),
349
+ createGiftCheckout: (recipientUsername, quantity, isAnonymous = false) => api.post(`${endpoint8}/create-gift-checkout`, {
350
+ recipientUsername,
351
+ quantity,
352
+ isAnonymous
353
+ }),
354
+ getGiftsHistory: () => api.get(`${endpoint8}/gifts-history`),
355
+ retryGiftAssignment: (purchaseId, recipientUsername) => api.post(`${endpoint8}/retry-gift-assignment`, {
356
+ purchaseId,
357
+ recipientUsername
358
+ })
319
359
  });
320
360
 
321
361
  // src/resources/friend.ts
@@ -374,7 +414,6 @@ var createApiClient = (config) => {
374
414
  };
375
415
  };
376
416
  export {
377
- Api,
378
417
  ApiError,
379
418
  Logger,
380
419
  createAdminResource,
package/package.json CHANGED
@@ -1,51 +1,50 @@
1
- {
2
- "name": "@borealise/api",
3
- "version": "2.0.0-alpha.9",
4
- "description": "Official API client for Borealise",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/index.mjs",
11
- "require": "./dist/index.js",
12
- "types": "./dist/index.d.ts"
13
- }
14
- },
15
- "files": [
16
- "dist",
17
- "README.md"
18
- ],
19
- "scripts": {
20
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
21
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
22
- "lint": "tsc --noEmit",
23
- "prepublishOnly": "npm run build"
24
- },
25
- "keywords": [
26
- "borealise",
27
- "api",
28
- "client",
29
- "music",
30
- "rooms"
31
- ],
32
- "author": "Borealise",
33
- "license": "MIT",
34
- "homepage": "https://borealise.com",
35
- "repository": {
36
- "type": "git",
37
- "url": "https://github.com/Borealise-Platform/api"
38
- },
39
- "bugs": {
40
- "url": "https://github.com/Borealise-Platform/api/issues"
41
- },
42
- "peerDependencies": {
43
- "axios": "^1.0.0"
44
- },
45
- "devDependencies": {
46
- "@types/node": "^20.0.0",
47
- "tsup": "^8.0.0",
48
- "typescript": "^5.0.0",
49
- "axios": "^1.6.0"
50
- }
51
- }
1
+ {
2
+ "name": "@borealise/api",
3
+ "version": "2.1.0-alpha.2",
4
+ "description": "Official API client for Borealise",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
21
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
22
+ "lint": "tsc --noEmit",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "borealise",
27
+ "api",
28
+ "client",
29
+ "music",
30
+ "rooms"
31
+ ],
32
+ "author": "Borealise",
33
+ "license": "MIT",
34
+ "homepage": "https://borealise.com",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/Borealise-Platform/api"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/Borealise-Platform/api/issues"
41
+ },
42
+ "dependencies": {
43
+ "ky": "^1.7.5"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^20.0.0",
47
+ "tsup": "^8.0.0",
48
+ "typescript": "^5.0.0"
49
+ }
50
+ }