@wavezfm/api 0.1.0

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.
Files changed (56) hide show
  1. package/README.md +338 -0
  2. package/dist/core/ApiError.d.ts +14 -0
  3. package/dist/core/ApiError.js +20 -0
  4. package/dist/core/ApiError.js.map +1 -0
  5. package/dist/core/api.d.ts +27 -0
  6. package/dist/core/api.js +327 -0
  7. package/dist/core/api.js.map +1 -0
  8. package/dist/core/i18n.d.ts +3 -0
  9. package/dist/core/i18n.js +97 -0
  10. package/dist/core/i18n.js.map +1 -0
  11. package/dist/index.d.ts +379 -0
  12. package/dist/index.js +47 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/realtime/roomBot.d.ts +2 -0
  15. package/dist/realtime/roomBot.js +215 -0
  16. package/dist/realtime/roomBot.js.map +1 -0
  17. package/dist/resources/auth.d.ts +35 -0
  18. package/dist/resources/auth.js +30 -0
  19. package/dist/resources/auth.js.map +1 -0
  20. package/dist/resources/billing.d.ts +45 -0
  21. package/dist/resources/billing.js +29 -0
  22. package/dist/resources/billing.js.map +1 -0
  23. package/dist/resources/chat.d.ts +27 -0
  24. package/dist/resources/chat.js +38 -0
  25. package/dist/resources/chat.js.map +1 -0
  26. package/dist/resources/friend.d.ts +23 -0
  27. package/dist/resources/friend.js +35 -0
  28. package/dist/resources/friend.js.map +1 -0
  29. package/dist/resources/playlist.d.ts +64 -0
  30. package/dist/resources/playlist.js +61 -0
  31. package/dist/resources/playlist.js.map +1 -0
  32. package/dist/resources/room.d.ts +50 -0
  33. package/dist/resources/room.js +152 -0
  34. package/dist/resources/room.js.map +1 -0
  35. package/dist/resources/roomBot.d.ts +45 -0
  36. package/dist/resources/roomBot.js +75 -0
  37. package/dist/resources/roomBot.js.map +1 -0
  38. package/dist/resources/settings.d.ts +43 -0
  39. package/dist/resources/settings.js +38 -0
  40. package/dist/resources/settings.js.map +1 -0
  41. package/dist/resources/shop.d.ts +11 -0
  42. package/dist/resources/shop.js +22 -0
  43. package/dist/resources/shop.js.map +1 -0
  44. package/dist/resources/source.d.ts +14 -0
  45. package/dist/resources/source.js +50 -0
  46. package/dist/resources/source.js.map +1 -0
  47. package/dist/resources/system.d.ts +6 -0
  48. package/dist/resources/system.js +20 -0
  49. package/dist/resources/system.js.map +1 -0
  50. package/dist/resources/user.d.ts +7 -0
  51. package/dist/resources/user.js +19 -0
  52. package/dist/resources/user.js.map +1 -0
  53. package/dist/types.d.ts +374 -0
  54. package/dist/types.js +2 -0
  55. package/dist/types.js.map +1 -0
  56. package/package.json +97 -0
package/README.md ADDED
@@ -0,0 +1,338 @@
1
+ # @wavezfm/api
2
+
3
+ Official JavaScript/TypeScript API client for Wavez.
4
+
5
+ This package is fetch-based and ships with zero runtime dependencies.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @wavezfm/api
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```ts
16
+ import { createApiClient } from '@wavezfm/api';
17
+
18
+ const client = createApiClient({
19
+ baseURL: 'https://api.wavez.example.com',
20
+ });
21
+
22
+ const rooms = await client.room.list();
23
+ console.log(rooms.data);
24
+ ```
25
+
26
+ ## Configuration
27
+
28
+ ```ts
29
+ createApiClient({
30
+ baseURL: 'https://api.wavez.example.com', // required
31
+ timeout: 15_000, // optional, default: 30000
32
+ logging: false, // optional
33
+ headers: { 'X-App-Version': '1.0.0' }, // optional
34
+ credentials: 'include', // optional, default: include
35
+ locale: 'en', // optional, default: en
36
+ })
37
+ ```
38
+
39
+ The client accepts either:
40
+
41
+ - `https://api.wavez.example.com`
42
+ - `https://wavez.example.com/api`
43
+ - `https://wavez.example.com`
44
+
45
+ If you use a dedicated API origin such as `api.wavez.example.com`, the SDK keeps root paths like `/rooms`.
46
+ If you pass the main site origin, the SDK still falls back to `/api`.
47
+
48
+ You can localize SDK-generated errors with `locale` or override specific messages with `messages`:
49
+
50
+ ```ts
51
+ const client = createApiClient({
52
+ baseURL: 'https://api.wavez.example.com',
53
+ locale: 'en',
54
+ messages: {
55
+ roomBotCreatePrefixLengthInvalid: 'Custom prefix length message.',
56
+ },
57
+ });
58
+ ```
59
+
60
+ ## Browser Session Auth
61
+
62
+ Wavez uses session cookies for most user-authenticated routes.
63
+
64
+ ```ts
65
+ const client = createApiClient({
66
+ baseURL: 'https://wavez.example.com/api',
67
+ });
68
+
69
+ await client.auth.login({
70
+ email: 'user@example.com',
71
+ password: 'secret',
72
+ });
73
+
74
+ const me = await client.auth.me();
75
+ if (me.data) {
76
+ console.log(me.data.displayUsername ?? me.data.username);
77
+ }
78
+ ```
79
+
80
+ For server-side Node integrations, room-bot routes are the best fit. Regular user routes rely on the browser session/cookie flow used by the site.
81
+
82
+ ## Room Bots
83
+
84
+ ```ts
85
+ const client = createApiClient({
86
+ baseURL: 'https://wavez.example.com/api',
87
+ });
88
+
89
+ client.api.setRoomBotToken(process.env.WAVEZ_ROOM_BOT_TOKEN!);
90
+
91
+ const state = await client.roomBot.getState('room-id');
92
+ console.log(state.data.bot);
93
+ ```
94
+
95
+ ## Realtime Room Bots
96
+
97
+ ```ts
98
+ import { createRoomBotRealtimeClient } from '@wavezfm/api';
99
+
100
+ const bot = createRoomBotRealtimeClient({
101
+ baseURL: 'https://wavez.example.com/api',
102
+ botToken: process.env.WAVEZ_ROOM_BOT_TOKEN!,
103
+ roomId: 'room-id',
104
+ locale: 'en',
105
+ });
106
+
107
+ bot.on('message_created', (packet) => {
108
+ console.log(packet.payload);
109
+ });
110
+
111
+ await bot.connect();
112
+ ```
113
+
114
+ ## Resources
115
+
116
+ All resources are exposed from the pre-configured client:
117
+
118
+ ```ts
119
+ const client = createApiClient({ baseURL: 'https://wavez.example.com/api' });
120
+ ```
121
+
122
+ ### Auth
123
+
124
+ ```ts
125
+ await client.auth.login({ email, password });
126
+ await client.auth.register({ email, password, name, username });
127
+ const me = await client.auth.me(); // returns `null` in `data` when there is no active session
128
+ await client.auth.getPendingTwoFactor();
129
+ await client.auth.sendPendingTwoFactorCode();
130
+ await client.auth.verifyPendingTwoFactor({ code: '123456' });
131
+ ```
132
+
133
+ ### Settings
134
+
135
+ ```ts
136
+ await client.settings.get();
137
+ await client.settings.update({
138
+ bio: 'Late-night selector',
139
+ presenceStatus: 'busy',
140
+ showChatBadge: true,
141
+ });
142
+ await client.settings.getTwoFactor();
143
+ await client.settings.startEmailTwoFactor({ password: 'secret' });
144
+ await client.settings.startAuthenticatorTwoFactor({ password: 'secret' });
145
+ await client.settings.disableTwoFactor({ password: 'secret' });
146
+ ```
147
+
148
+ ### Users
149
+
150
+ ```ts
151
+ await client.user.getById('user-id');
152
+ await client.user.getByUsername('haru');
153
+ await client.user.getBadges('user-id');
154
+ await client.user.listAllBadges();
155
+ ```
156
+
157
+ ### Rooms
158
+
159
+ ```ts
160
+ await client.room.list();
161
+ await client.room.featured();
162
+ await client.room.getBySlug('wavez-lounge');
163
+ await client.room.getWaitlist('wavez-lounge');
164
+ await client.room.create({ slug: 'my-room', name: 'My Room' });
165
+ await client.room.join('wavez-lounge');
166
+ await client.room.favorite('room-id');
167
+ await client.room.getManagement('room-id');
168
+ await client.room.createBotToken('room-id', {
169
+ botName: 'Night Shift Bot',
170
+ commandPrefix: '!',
171
+ permissions: ['read_state', 'read_chat', 'send_chat', 'manage_room'],
172
+ });
173
+ ```
174
+
175
+ ### Playlists
176
+
177
+ ```ts
178
+ await client.playlist.list();
179
+ await client.playlist.create('My Playlist');
180
+ await client.playlist.update('playlist-id', { name: 'Late Night Set' });
181
+ await client.playlist.getTracks('playlist-id');
182
+ await client.playlist.previewUrl('https://youtube.com/watch?v=dQw4w9WgXcQ');
183
+ await client.playlist.addTrack('playlist-id', {
184
+ source: 'youtube',
185
+ sourceId: 'dQw4w9WgXcQ',
186
+ });
187
+ await client.playlist.reorderTracks('playlist-id', ['track-a', 'track-b']);
188
+ await client.playlist.startSpotifyImport({
189
+ playlistId: 'playlist-id',
190
+ url: 'https://open.spotify.com/playlist/...',
191
+ });
192
+ ```
193
+
194
+ ### Sources
195
+
196
+ ```ts
197
+ await client.source.searchYouTube('lofi hip hop', 10);
198
+ await client.source.searchSoundCloud('nightcore', 10);
199
+ await client.source.searchAll('ambient');
200
+ ```
201
+
202
+ ### Chat
203
+
204
+ ```ts
205
+ await client.chat.getMessages('room-id', 0, 50);
206
+ await client.chat.getMessagesBySlug('wavez-lounge', 0, 50);
207
+ await client.chat.updateMessage('room-id', 'message-id', {
208
+ content: 'edited message',
209
+ });
210
+ await client.chat.pinMessage('room-id', 'message-id');
211
+ await client.chat.clearChat('room-id');
212
+ ```
213
+
214
+ ### Friends / Fans
215
+
216
+ ```ts
217
+ await client.friend.list();
218
+ await client.friend.pending();
219
+ await client.friend.sendRequest('user-id');
220
+ await client.friend.acceptRequest('request-id');
221
+ await client.friend.follow('user-id');
222
+ await client.friend.followers();
223
+ ```
224
+
225
+ ### Shop
226
+
227
+ ```ts
228
+ await client.shop.getCatalog();
229
+ await client.shop.getWallet();
230
+ await client.shop.purchase({ itemId: 'badge-id' });
231
+ await client.shop.equip('avatar-id');
232
+ await client.shop.getInventory();
233
+ ```
234
+
235
+ ### Billing
236
+
237
+ ```ts
238
+ await client.billing.createSubscriptionCheckout({ cycle: 'monthly' });
239
+ await client.billing.createDiamondCheckout({ quantity: 1000 });
240
+ await client.billing.createRoomDonationCheckout('room-id', { amountCents: 500 });
241
+ await client.billing.createGlobalDonationCheckout({ amountCents: 1000 });
242
+ await client.billing.createDiamondGiftCheckout({
243
+ recipientUsername: 'haru',
244
+ quantity: 500,
245
+ });
246
+ await client.billing.listPendingGifts();
247
+ ```
248
+
249
+ ### System
250
+
251
+ ```ts
252
+ await client.system.status();
253
+ await client.system.publicStats();
254
+ await client.system.health();
255
+ ```
256
+
257
+ ### Room Bots
258
+
259
+ ```ts
260
+ client.api.setRoomBotToken(process.env.WAVEZ_ROOM_BOT_TOKEN!);
261
+
262
+ await client.roomBot.getState('room-id');
263
+ await client.roomBot.getMessages('room-id');
264
+ await client.roomBot.sendMessage('room-id', { content: '!lockqueue' });
265
+ await client.roomBot.updateSettings('room-id', {
266
+ queueLocked: true,
267
+ commandAnnouncement: {
268
+ commandId: 'lockqueue',
269
+ actorUsername: 'Night Shift Bot',
270
+ },
271
+ });
272
+ ```
273
+
274
+ ## Error Handling
275
+
276
+ All methods throw `ApiError` on failure.
277
+
278
+ ```ts
279
+ import { ApiError } from '@wavezfm/api';
280
+
281
+ try {
282
+ await client.auth.login({ email: 'bad@example.com', password: 'bad' });
283
+ } catch (error) {
284
+ if (error instanceof ApiError) {
285
+ console.log(error.message);
286
+ console.log(error.status);
287
+ console.log(error.code);
288
+ console.log(error.response);
289
+ }
290
+ }
291
+ ```
292
+
293
+ ## Token Management
294
+
295
+ ```ts
296
+ const client = createApiClient({ baseURL: 'https://wavez.example.com/api' });
297
+
298
+ client.api.setAuthToken('optional-bearer-token');
299
+ client.api.setRoomBotToken(process.env.WAVEZ_ROOM_BOT_TOKEN!);
300
+
301
+ client.api.getAuthToken();
302
+ client.api.getRoomBotToken();
303
+ ```
304
+
305
+ ## Tree-Shaking
306
+
307
+ For maximum tree-shaking, import only what you need:
308
+
309
+ ```ts
310
+ import { createApi } from '@wavezfm/api';
311
+ import { createRoomResource } from '@wavezfm/api/resources/room';
312
+ import { createRoomBotResource } from '@wavezfm/api/resources/room-bot';
313
+
314
+ const api = createApi({ baseURL: 'https://wavez.example.com/api' });
315
+ const room = createRoomResource(api);
316
+ const roomBot = createRoomBotResource(api);
317
+ ```
318
+
319
+ ## TypeScript
320
+
321
+ ```ts
322
+ import type {
323
+ AuthUser,
324
+ RoomSummary,
325
+ PlaylistTrack,
326
+ MediaSearchResult,
327
+ ChatMessage,
328
+ RoomBotState,
329
+ WsPacket,
330
+ } from '@wavezfm/api';
331
+ ```
332
+
333
+ ## Notes
334
+
335
+ - user/session routes are browser-first because the backend uses cookies and same-origin protections
336
+ - room-bot routes are ideal for backend integrations and automation
337
+ - the package is tree-shakable through factory exports in `resources/*`
338
+ - the realtime helper expects native `WebSocket` or a custom `websocketFactory`
@@ -0,0 +1,14 @@
1
+ export declare class ApiError extends Error {
2
+ readonly status: number;
3
+ readonly statusText: string;
4
+ readonly code: string | null;
5
+ readonly response: unknown;
6
+ readonly headers: Headers;
7
+ constructor(message: string, input: {
8
+ status: number;
9
+ statusText?: string;
10
+ code?: string | null;
11
+ response?: unknown;
12
+ headers?: Headers;
13
+ });
14
+ }
@@ -0,0 +1,20 @@
1
+ export class ApiError extends Error {
2
+ status;
3
+ statusText;
4
+ code;
5
+ response;
6
+ headers;
7
+ constructor(message, input) {
8
+ super(message);
9
+ this.name = "ApiError";
10
+ this.status = input.status;
11
+ this.statusText = input.statusText ?? "";
12
+ this.code =
13
+ typeof input.code === "string" && input.code.trim().length > 0
14
+ ? input.code
15
+ : null;
16
+ this.response = input.response ?? null;
17
+ this.headers = input.headers ?? new Headers();
18
+ }
19
+ }
20
+ //# sourceMappingURL=ApiError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiError.js","sourceRoot":"","sources":["../../src/core/ApiError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACtB,MAAM,CAAS;IACf,UAAU,CAAS;IACnB,IAAI,CAAgB;IACpB,QAAQ,CAAU;IAClB,OAAO,CAAU;IAE1B,YACI,OAAe,EACf,KAMC;QAED,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI;YACL,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;gBAC1D,CAAC,CAAC,KAAK,CAAC,IAAI;gBACZ,CAAC,CAAC,IAAI,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,OAAO,EAAE,CAAC;IAClD,CAAC;CACJ"}
@@ -0,0 +1,27 @@
1
+ import type { ApiClientConfig, ApiLike, ApiRequestOptions, ApiSuccessResponse, WavezApiMessageKey, WavezApiMessageValues } from "../types";
2
+ export declare class WavezApi implements ApiLike {
3
+ private readonly baseURL;
4
+ private readonly defaultHeaders;
5
+ private readonly timeout;
6
+ private readonly credentials;
7
+ private readonly fetchImpl;
8
+ private readonly logging;
9
+ private readonly messageFormatter;
10
+ private authToken;
11
+ private roomBotToken;
12
+ constructor(config: ApiClientConfig);
13
+ getBaseURL(): string;
14
+ getSiteURL(path?: string): string;
15
+ formatMessage(key: WavezApiMessageKey, values?: WavezApiMessageValues): string;
16
+ setAuthToken(token: string | null): void;
17
+ getAuthToken(): string | null;
18
+ setRoomBotToken(token: string | null): void;
19
+ getRoomBotToken(): string | null;
20
+ request<T, TBody = unknown>(options: ApiRequestOptions<TBody>): Promise<ApiSuccessResponse<T>>;
21
+ get<T>(path: string, options?: Omit<ApiRequestOptions<never>, "path" | "method" | "body">): Promise<ApiSuccessResponse<T>>;
22
+ post<T, TBody = unknown>(path: string, body?: TBody, options?: Omit<ApiRequestOptions<TBody>, "path" | "method" | "body">): Promise<ApiSuccessResponse<T>>;
23
+ put<T, TBody = unknown>(path: string, body?: TBody, options?: Omit<ApiRequestOptions<TBody>, "path" | "method" | "body">): Promise<ApiSuccessResponse<T>>;
24
+ patch<T, TBody = unknown>(path: string, body?: TBody, options?: Omit<ApiRequestOptions<TBody>, "path" | "method" | "body">): Promise<ApiSuccessResponse<T>>;
25
+ delete<T, TBody = unknown>(path: string, options?: Omit<ApiRequestOptions<TBody>, "path" | "method">): Promise<ApiSuccessResponse<T>>;
26
+ }
27
+ export declare function createApi(config: ApiClientConfig): WavezApi;