rotur-sdk 1.0.0 → 1.0.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 +302 -0
- package/dist/index.d.mts +13 -23
- package/dist/index.d.ts +13 -23
- package/dist/index.js +55 -22
- package/dist/index.mjs +55 -22
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# rotur-sdk
|
|
2
|
+
|
|
3
|
+
The official TypeScript SDK for the [Rotur](https://rotur.dev) platform. Covers auth, profiles, posts, credits, keys, groups, items, gifts, tokens, validators, status, files, cosmetics, push notifications, and more — all with full type safety.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install rotur-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Rotur } from "rotur-sdk";
|
|
15
|
+
|
|
16
|
+
const rotur = new Rotur();
|
|
17
|
+
|
|
18
|
+
// Browser auth - opens the Rotur login popup
|
|
19
|
+
await rotur.login();
|
|
20
|
+
|
|
21
|
+
// Or provide a token you already have
|
|
22
|
+
const rotur = new Rotur({ token: "your-token-here" });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## API Reference
|
|
26
|
+
|
|
27
|
+
### Authentication
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// Popup-based OAuth flow (browser only)
|
|
31
|
+
await rotur.login({ system: "my-app", timeout: 60_000 });
|
|
32
|
+
|
|
33
|
+
// Check current auth state
|
|
34
|
+
rotur.loggedIn; // boolean
|
|
35
|
+
rotur.token; // string | null
|
|
36
|
+
|
|
37
|
+
// Set/refresh token manually
|
|
38
|
+
rotur.setToken("new-token");
|
|
39
|
+
|
|
40
|
+
// Logout (clears token + disconnects socket)
|
|
41
|
+
rotur.logout();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Link-based Auth (for CLI / server)
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
const code = await rotur.link.getCode();
|
|
48
|
+
console.log(`Visit https://rotur.dev/link and enter: ${code}`);
|
|
49
|
+
|
|
50
|
+
// Polls until the user links on the website
|
|
51
|
+
const token = await rotur.link.pollUntilLinked(code);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Profiles
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const profile = await rotur.profiles.get("username");
|
|
58
|
+
const { exists } = await rotur.profiles.exists("username");
|
|
59
|
+
const avatarUrl = rotur.profiles.getAvatarUrl("username");
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Account (me)
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
await rotur.me.get();
|
|
66
|
+
await rotur.me.update("bio", "hello world");
|
|
67
|
+
await rotur.me.transfer("recipient", 100, "a note");
|
|
68
|
+
await rotur.me.claimDaily();
|
|
69
|
+
await rotur.me.badges();
|
|
70
|
+
await rotur.me.block("username");
|
|
71
|
+
await rotur.me.unblock("username");
|
|
72
|
+
await rotur.me.checkAuth();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Posts
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const post = await rotur.posts.create("Hello from the SDK!");
|
|
79
|
+
await rotur.posts.reply(post.id, "Nice post!");
|
|
80
|
+
await rotur.posts.like(post.id);
|
|
81
|
+
await rotur.posts.repost(post.id);
|
|
82
|
+
await rotur.posts.pin(post.id);
|
|
83
|
+
|
|
84
|
+
const feed = await rotur.posts.feed(100, 0);
|
|
85
|
+
const top = await rotur.posts.top(50, 24);
|
|
86
|
+
const results = await rotur.posts.search("query");
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Friends
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const { friends } = await rotur.friends.list();
|
|
93
|
+
await rotur.friends.request("username");
|
|
94
|
+
await rotur.friends.accept("username");
|
|
95
|
+
await rotur.friends.remove("username");
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Following
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
await rotur.following.follow("username");
|
|
102
|
+
await rotur.following.unfollow("username");
|
|
103
|
+
const { followers } = await rotur.following.followers("username");
|
|
104
|
+
const { following } = await rotur.following.following("username");
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Keys
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
await rotur.keys.create("my-key", { price: 50, subscription: true });
|
|
111
|
+
const myKeys = await rotur.keys.mine();
|
|
112
|
+
const key = await rotur.keys.get("key-id");
|
|
113
|
+
const { owned } = await rotur.keys.check("username", "key-name");
|
|
114
|
+
await rotur.keys.buy("key-id");
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Items
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const item = await rotur.items.create({ name: "sword", price: 100, selling: true });
|
|
121
|
+
const item = await rotur.items.get("sword");
|
|
122
|
+
const items = await rotur.items.list("username");
|
|
123
|
+
await rotur.items.buy("sword");
|
|
124
|
+
await rotur.items.sell("sword");
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Gifts
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
await rotur.gifts.create(500, { note: "Happy birthday!", expiresInHrs: 48 });
|
|
131
|
+
const { gift } = await rotur.gifts.get("code");
|
|
132
|
+
await rotur.gifts.claim("code");
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Tokens (sub-tokens / scoped access)
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const { permissions, groups } = await rotur.tokens.permissions();
|
|
139
|
+
const { tokens } = await rotur.tokens.list();
|
|
140
|
+
|
|
141
|
+
const sub = await rotur.tokens.create("bot-token", [
|
|
142
|
+
"posts:view", "posts:create", "account:profile"
|
|
143
|
+
], { expiresInHrs: 24, origin: "my-app" });
|
|
144
|
+
|
|
145
|
+
await rotur.tokens.revoke(sub.id);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Groups
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const group = await rotur.groups.create("devs", "Developers", {
|
|
152
|
+
description: "A group for devs",
|
|
153
|
+
public: true,
|
|
154
|
+
joinPolicy: "OPEN",
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
await rotur.groups.join("devs");
|
|
158
|
+
await rotur.groups.represent("devs");
|
|
159
|
+
const announcements = await rotur.groups.announcements("devs");
|
|
160
|
+
const roles = await rotur.groups.roles("devs");
|
|
161
|
+
await rotur.groups.assignRole("devs", userId, roleId);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Cosmetics
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
const shop = await rotur.cosmetics.shop({ sort: "newest", limit: 20 });
|
|
168
|
+
const mine = await rotur.cosmetics.mine();
|
|
169
|
+
await rotur.cosmetics.purchase("cosmetic-id");
|
|
170
|
+
await rotur.cosmetics.equip("cosmetic-id");
|
|
171
|
+
await rotur.cosmetics.unequip("hat");
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Files
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
const files = await rotur.files.index();
|
|
178
|
+
const { used, max } = await rotur.files.usage();
|
|
179
|
+
const file = await rotur.files.getByUUID("uuid");
|
|
180
|
+
const file = await rotur.files.getByPath("path/to/file");
|
|
181
|
+
await rotur.files.upload({ /* file data */ });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Push Notifications
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
const { public_key } = await rotur.push.vapidKeys();
|
|
188
|
+
await rotur.push.register(endpoint, p256dh, auth, "my-app", "fingerprint");
|
|
189
|
+
const { endpoints } = await rotur.push.endpoints();
|
|
190
|
+
await rotur.push.send("username", "my-app", { title: "Hi!", body: "You have a message" });
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Status & Validators
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const status = await rotur.status.get("username");
|
|
197
|
+
const { validator } = await rotur.validators.generate("key");
|
|
198
|
+
const result = await rotur.validators.validate(validator, "key");
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Standing, Stats, DevFund, Check
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
const standing = await rotur.standing.get("username");
|
|
205
|
+
const economy = await rotur.stats.economy();
|
|
206
|
+
await rotur.devfund.escrowTransfer(100, "petition-id");
|
|
207
|
+
const { banned } = await rotur.check.banned(["user1", "user2"]);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## WebSocket (Real-time)
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
// Connect after login
|
|
214
|
+
const { user_id, username } = await rotur.connectSocket();
|
|
215
|
+
|
|
216
|
+
// Join presence rooms
|
|
217
|
+
rotur.socket.join(["lobby", "chat"]);
|
|
218
|
+
|
|
219
|
+
// Listen for events
|
|
220
|
+
rotur.socket.on("member_join", (msg) => {
|
|
221
|
+
console.log(`${msg.username} joined ${msg.room}`);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
rotur.socket.on("status_update", (msg) => {
|
|
225
|
+
console.log(`${msg.username} is now ${msg.presence}`);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Set your own status
|
|
229
|
+
rotur.socket.setStatus("Building something cool", "online");
|
|
230
|
+
|
|
231
|
+
// Rich presence — "Playing" activity
|
|
232
|
+
rotur.socket.setPlaying("My Game", {
|
|
233
|
+
title: "Level 3",
|
|
234
|
+
status: "In-game",
|
|
235
|
+
url: "https://mygame.com",
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// "Listening to" activity
|
|
239
|
+
rotur.socket.setMusic("Spotify", {
|
|
240
|
+
title: "Song Name",
|
|
241
|
+
artist: "Artist",
|
|
242
|
+
album: "Album",
|
|
243
|
+
start: Date.now(),
|
|
244
|
+
end: Date.now() + 180_000,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Wildcard — receive every message
|
|
248
|
+
rotur.socket.on("*", (msg) => console.log(msg.cmd, msg));
|
|
249
|
+
|
|
250
|
+
// Disconnect
|
|
251
|
+
rotur.socket.disconnect();
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The socket auto-reconnects with exponential backoff and sends heartbeats every 25s.
|
|
255
|
+
|
|
256
|
+
## Error Handling
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
import { ApiError, AuthError } from "rotur-sdk";
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
await rotur.me.transfer("user", 1000);
|
|
263
|
+
} catch (e) {
|
|
264
|
+
if (e instanceof ApiError) {
|
|
265
|
+
console.log(e.status); // HTTP status code
|
|
266
|
+
console.log(e.data); // response body
|
|
267
|
+
console.log(e.message); // human-readable error
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
await rotur.login();
|
|
273
|
+
} catch (e) {
|
|
274
|
+
if (e instanceof AuthError) {
|
|
275
|
+
console.log(e.code); // "timeout" | "aborted" | "popup_blocked" | "no_token"
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Building
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npm run build # build CJS + ESM + types via tsup
|
|
284
|
+
npm run dev # watch mode
|
|
285
|
+
npm run typecheck # tsc --noEmit
|
|
286
|
+
npm test # vitest
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Exports
|
|
290
|
+
|
|
291
|
+
| Export | Description |
|
|
292
|
+
|---|---|
|
|
293
|
+
| `Rotur` | Main client class |
|
|
294
|
+
| `RoturSocket` | WebSocket connection (real-time presence) |
|
|
295
|
+
| `ApiError` | HTTP error with `status` and `data` |
|
|
296
|
+
| `performAuth`, `AuthError` | Browser auth flow |
|
|
297
|
+
| `AuthOptions`, `AuthResult` | Auth option types |
|
|
298
|
+
| All types from `types.ts` | `UserProfile`, `NetPost`, `GroupPublic`, `WSMessage`, etc. |
|
|
299
|
+
|
|
300
|
+
## License
|
|
301
|
+
|
|
302
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -496,6 +496,7 @@ type WSMessage = {
|
|
|
496
496
|
};
|
|
497
497
|
|
|
498
498
|
type Handler = (msg: any) => void;
|
|
499
|
+
type KeyChangeCallback = (key: string, value: any, oldValue: any) => void;
|
|
499
500
|
declare class RoturSocket extends EventTarget {
|
|
500
501
|
private url;
|
|
501
502
|
private ws;
|
|
@@ -507,11 +508,18 @@ declare class RoturSocket extends EventTarget {
|
|
|
507
508
|
private _username;
|
|
508
509
|
private handlers;
|
|
509
510
|
private rooms;
|
|
511
|
+
private keyCache;
|
|
512
|
+
private keyChangeCallbacks;
|
|
510
513
|
constructor(url?: string);
|
|
511
514
|
get connected(): boolean;
|
|
512
515
|
get userId(): string | null;
|
|
513
516
|
get username(): string | null;
|
|
514
517
|
get joinedRooms(): string[];
|
|
518
|
+
getKey(key: string): any;
|
|
519
|
+
getAllKeys(): Record<string, any>;
|
|
520
|
+
onKeyChange(callback: KeyChangeCallback): () => void;
|
|
521
|
+
offKeyChange(callback: KeyChangeCallback): void;
|
|
522
|
+
private notifyKeyChange;
|
|
515
523
|
connect(token: string): Promise<{
|
|
516
524
|
user_id: UserId;
|
|
517
525
|
username: Username;
|
|
@@ -529,8 +537,7 @@ declare class RoturSocket extends EventTarget {
|
|
|
529
537
|
leave(rooms: string | string[]): void;
|
|
530
538
|
listRooms(): Promise<string[]>;
|
|
531
539
|
roomState(room: string): void;
|
|
532
|
-
|
|
533
|
-
setStatus(status: string): void;
|
|
540
|
+
setStatus(status: string, presence?: Presence): void;
|
|
534
541
|
addActivity(activity: Activity & {
|
|
535
542
|
id: string;
|
|
536
543
|
}): void;
|
|
@@ -579,6 +586,7 @@ declare class Rotur {
|
|
|
579
586
|
get token(): string | null;
|
|
580
587
|
get loggedIn(): boolean;
|
|
581
588
|
setToken(token: string): void;
|
|
589
|
+
private _socketReady;
|
|
582
590
|
login(options?: {
|
|
583
591
|
system?: string;
|
|
584
592
|
timeout?: number;
|
|
@@ -616,6 +624,9 @@ declare class MeNamespace extends Namespace {
|
|
|
616
624
|
refreshToken(): Promise<{
|
|
617
625
|
token: string;
|
|
618
626
|
}>;
|
|
627
|
+
getKey(key: string): any;
|
|
628
|
+
getAllKeys(): Record<string, any>;
|
|
629
|
+
onKeyChange(callback: (key: string, value: any, oldValue: any) => void): () => void;
|
|
619
630
|
transfer(to: Username, amount: number, note?: string): Promise<any>;
|
|
620
631
|
claimDaily(): Promise<{
|
|
621
632
|
message: string;
|
|
@@ -875,27 +886,6 @@ declare class CosmeticsNamespace extends Namespace {
|
|
|
875
886
|
message: string;
|
|
876
887
|
}>;
|
|
877
888
|
overlays(filepath: string): Promise<Response>;
|
|
878
|
-
/** Admin: List all cosmetics in catalog */
|
|
879
|
-
adminList(options?: {
|
|
880
|
-
type?: string;
|
|
881
|
-
}): Promise<{
|
|
882
|
-
cosmetics: CosmeticCatalogEntryPublic[];
|
|
883
|
-
total: number;
|
|
884
|
-
}>;
|
|
885
|
-
/** Admin: Create a cosmetic */
|
|
886
|
-
adminCreate(data: AdminCosmeticCreate): Promise<{
|
|
887
|
-
message: string;
|
|
888
|
-
cosmetic: CosmeticCatalogEntryPublic;
|
|
889
|
-
}>;
|
|
890
|
-
/** Admin: Update a cosmetic */
|
|
891
|
-
adminUpdate(id: string, data: AdminCosmeticUpdate): Promise<{
|
|
892
|
-
message: string;
|
|
893
|
-
cosmetic: CosmeticCatalogEntryPublic;
|
|
894
|
-
}>;
|
|
895
|
-
/** Admin: Delete a cosmetic */
|
|
896
|
-
adminDelete(id: string): Promise<{
|
|
897
|
-
message: string;
|
|
898
|
-
}>;
|
|
899
889
|
}
|
|
900
890
|
declare class PushNamespace extends Namespace {
|
|
901
891
|
vapidKeys(): Promise<{
|
package/dist/index.d.ts
CHANGED
|
@@ -496,6 +496,7 @@ type WSMessage = {
|
|
|
496
496
|
};
|
|
497
497
|
|
|
498
498
|
type Handler = (msg: any) => void;
|
|
499
|
+
type KeyChangeCallback = (key: string, value: any, oldValue: any) => void;
|
|
499
500
|
declare class RoturSocket extends EventTarget {
|
|
500
501
|
private url;
|
|
501
502
|
private ws;
|
|
@@ -507,11 +508,18 @@ declare class RoturSocket extends EventTarget {
|
|
|
507
508
|
private _username;
|
|
508
509
|
private handlers;
|
|
509
510
|
private rooms;
|
|
511
|
+
private keyCache;
|
|
512
|
+
private keyChangeCallbacks;
|
|
510
513
|
constructor(url?: string);
|
|
511
514
|
get connected(): boolean;
|
|
512
515
|
get userId(): string | null;
|
|
513
516
|
get username(): string | null;
|
|
514
517
|
get joinedRooms(): string[];
|
|
518
|
+
getKey(key: string): any;
|
|
519
|
+
getAllKeys(): Record<string, any>;
|
|
520
|
+
onKeyChange(callback: KeyChangeCallback): () => void;
|
|
521
|
+
offKeyChange(callback: KeyChangeCallback): void;
|
|
522
|
+
private notifyKeyChange;
|
|
515
523
|
connect(token: string): Promise<{
|
|
516
524
|
user_id: UserId;
|
|
517
525
|
username: Username;
|
|
@@ -529,8 +537,7 @@ declare class RoturSocket extends EventTarget {
|
|
|
529
537
|
leave(rooms: string | string[]): void;
|
|
530
538
|
listRooms(): Promise<string[]>;
|
|
531
539
|
roomState(room: string): void;
|
|
532
|
-
|
|
533
|
-
setStatus(status: string): void;
|
|
540
|
+
setStatus(status: string, presence?: Presence): void;
|
|
534
541
|
addActivity(activity: Activity & {
|
|
535
542
|
id: string;
|
|
536
543
|
}): void;
|
|
@@ -579,6 +586,7 @@ declare class Rotur {
|
|
|
579
586
|
get token(): string | null;
|
|
580
587
|
get loggedIn(): boolean;
|
|
581
588
|
setToken(token: string): void;
|
|
589
|
+
private _socketReady;
|
|
582
590
|
login(options?: {
|
|
583
591
|
system?: string;
|
|
584
592
|
timeout?: number;
|
|
@@ -616,6 +624,9 @@ declare class MeNamespace extends Namespace {
|
|
|
616
624
|
refreshToken(): Promise<{
|
|
617
625
|
token: string;
|
|
618
626
|
}>;
|
|
627
|
+
getKey(key: string): any;
|
|
628
|
+
getAllKeys(): Record<string, any>;
|
|
629
|
+
onKeyChange(callback: (key: string, value: any, oldValue: any) => void): () => void;
|
|
619
630
|
transfer(to: Username, amount: number, note?: string): Promise<any>;
|
|
620
631
|
claimDaily(): Promise<{
|
|
621
632
|
message: string;
|
|
@@ -875,27 +886,6 @@ declare class CosmeticsNamespace extends Namespace {
|
|
|
875
886
|
message: string;
|
|
876
887
|
}>;
|
|
877
888
|
overlays(filepath: string): Promise<Response>;
|
|
878
|
-
/** Admin: List all cosmetics in catalog */
|
|
879
|
-
adminList(options?: {
|
|
880
|
-
type?: string;
|
|
881
|
-
}): Promise<{
|
|
882
|
-
cosmetics: CosmeticCatalogEntryPublic[];
|
|
883
|
-
total: number;
|
|
884
|
-
}>;
|
|
885
|
-
/** Admin: Create a cosmetic */
|
|
886
|
-
adminCreate(data: AdminCosmeticCreate): Promise<{
|
|
887
|
-
message: string;
|
|
888
|
-
cosmetic: CosmeticCatalogEntryPublic;
|
|
889
|
-
}>;
|
|
890
|
-
/** Admin: Update a cosmetic */
|
|
891
|
-
adminUpdate(id: string, data: AdminCosmeticUpdate): Promise<{
|
|
892
|
-
message: string;
|
|
893
|
-
cosmetic: CosmeticCatalogEntryPublic;
|
|
894
|
-
}>;
|
|
895
|
-
/** Admin: Delete a cosmetic */
|
|
896
|
-
adminDelete(id: string): Promise<{
|
|
897
|
-
message: string;
|
|
898
|
-
}>;
|
|
899
889
|
}
|
|
900
890
|
declare class PushNamespace extends Namespace {
|
|
901
891
|
vapidKeys(): Promise<{
|
package/dist/index.js
CHANGED
|
@@ -139,6 +139,8 @@ var RoturSocket = class extends EventTarget {
|
|
|
139
139
|
_username = null;
|
|
140
140
|
handlers = /* @__PURE__ */ new Map();
|
|
141
141
|
rooms = /* @__PURE__ */ new Set();
|
|
142
|
+
keyCache = {};
|
|
143
|
+
keyChangeCallbacks = /* @__PURE__ */ new Set();
|
|
142
144
|
get connected() {
|
|
143
145
|
return this._connected;
|
|
144
146
|
}
|
|
@@ -151,6 +153,27 @@ var RoturSocket = class extends EventTarget {
|
|
|
151
153
|
get joinedRooms() {
|
|
152
154
|
return [...this.rooms];
|
|
153
155
|
}
|
|
156
|
+
getKey(key) {
|
|
157
|
+
return this.keyCache[key];
|
|
158
|
+
}
|
|
159
|
+
getAllKeys() {
|
|
160
|
+
return { ...this.keyCache };
|
|
161
|
+
}
|
|
162
|
+
onKeyChange(callback) {
|
|
163
|
+
this.keyChangeCallbacks.add(callback);
|
|
164
|
+
return () => this.keyChangeCallbacks.delete(callback);
|
|
165
|
+
}
|
|
166
|
+
offKeyChange(callback) {
|
|
167
|
+
this.keyChangeCallbacks.delete(callback);
|
|
168
|
+
}
|
|
169
|
+
notifyKeyChange(key, value, oldValue) {
|
|
170
|
+
for (const cb of this.keyChangeCallbacks) {
|
|
171
|
+
try {
|
|
172
|
+
cb(key, value, oldValue);
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
154
177
|
connect(token) {
|
|
155
178
|
this.token = token;
|
|
156
179
|
return new Promise((resolve, reject) => {
|
|
@@ -168,11 +191,19 @@ var RoturSocket = class extends EventTarget {
|
|
|
168
191
|
this._connected = true;
|
|
169
192
|
this._userId = msg.user_id;
|
|
170
193
|
this._username = msg.username;
|
|
194
|
+
if (msg.user && typeof msg.user === "object") {
|
|
195
|
+
this.keyCache = { ...msg.user };
|
|
196
|
+
}
|
|
171
197
|
this.startHeartbeat();
|
|
172
198
|
resolve(msg);
|
|
173
199
|
}
|
|
174
200
|
if (cmd === "join_ok") this.rooms.add(msg.room);
|
|
175
201
|
if (cmd === "leave_ok") this.rooms.delete(msg.room);
|
|
202
|
+
if (cmd === "key_update" && typeof msg.key === "string") {
|
|
203
|
+
const old = this.keyCache[msg.key];
|
|
204
|
+
this.keyCache[msg.key] = msg.value;
|
|
205
|
+
this.notifyKeyChange(msg.key, msg.value, old);
|
|
206
|
+
}
|
|
176
207
|
this.emit(cmd, msg);
|
|
177
208
|
};
|
|
178
209
|
this.ws.onerror = (e) => {
|
|
@@ -248,11 +279,8 @@ var RoturSocket = class extends EventTarget {
|
|
|
248
279
|
roomState(room) {
|
|
249
280
|
this.send({ cmd: "room_state", room });
|
|
250
281
|
}
|
|
251
|
-
|
|
252
|
-
this.send({ cmd: "set_status", presence });
|
|
253
|
-
}
|
|
254
|
-
setStatus(status) {
|
|
255
|
-
this.send({ cmd: "set_status", status });
|
|
282
|
+
setStatus(status, presence) {
|
|
283
|
+
this.send({ cmd: "set_status", status, presence });
|
|
256
284
|
}
|
|
257
285
|
addActivity(activity) {
|
|
258
286
|
this.send({ cmd: "add_activity", ...activity });
|
|
@@ -286,6 +314,7 @@ var RoturSocket = class extends EventTarget {
|
|
|
286
314
|
this.token = null;
|
|
287
315
|
this.cleanup();
|
|
288
316
|
this.rooms.clear();
|
|
317
|
+
this.keyCache = {};
|
|
289
318
|
if (this.ws) {
|
|
290
319
|
this.ws.onclose = null;
|
|
291
320
|
this.ws.close();
|
|
@@ -383,6 +412,9 @@ var Rotur = class {
|
|
|
383
412
|
this._token = options?.token ?? null;
|
|
384
413
|
this._http = new Http(() => this._token);
|
|
385
414
|
this.socket = new RoturSocket(options?.wsUrl);
|
|
415
|
+
if (this._token) {
|
|
416
|
+
this._socketReady = this.socket.connect(this._token).catch(() => null);
|
|
417
|
+
}
|
|
386
418
|
}
|
|
387
419
|
get token() {
|
|
388
420
|
return this._token;
|
|
@@ -392,18 +424,26 @@ var Rotur = class {
|
|
|
392
424
|
}
|
|
393
425
|
setToken(token) {
|
|
394
426
|
this._token = token;
|
|
427
|
+
if (!this.socket.connected) {
|
|
428
|
+
this._socketReady = this.socket.connect(this._token).catch(() => null);
|
|
429
|
+
}
|
|
395
430
|
}
|
|
431
|
+
_socketReady = null;
|
|
396
432
|
async login(options) {
|
|
397
433
|
const { token } = await performAuth(options);
|
|
398
434
|
this._token = token;
|
|
435
|
+
this._socketReady = this.socket.connect(this._token).catch(() => null);
|
|
399
436
|
return this;
|
|
400
437
|
}
|
|
401
438
|
async connectSocket() {
|
|
402
439
|
if (!this._token) throw new ApiError(401, { error: "Login first" });
|
|
403
|
-
|
|
440
|
+
const result = await this.socket.connect(this._token);
|
|
441
|
+
this._socketReady = Promise.resolve(result);
|
|
442
|
+
return result;
|
|
404
443
|
}
|
|
405
444
|
logout() {
|
|
406
445
|
this._token = null;
|
|
446
|
+
this._socketReady = null;
|
|
407
447
|
this.socket.disconnect();
|
|
408
448
|
}
|
|
409
449
|
};
|
|
@@ -459,6 +499,15 @@ var MeNamespace = class extends Namespace {
|
|
|
459
499
|
async refreshToken() {
|
|
460
500
|
return this.$post("/me/refresh_token");
|
|
461
501
|
}
|
|
502
|
+
getKey(key) {
|
|
503
|
+
return this.r.socket.getKey(key);
|
|
504
|
+
}
|
|
505
|
+
getAllKeys() {
|
|
506
|
+
return this.r.socket.getAllKeys();
|
|
507
|
+
}
|
|
508
|
+
onKeyChange(callback) {
|
|
509
|
+
return this.r.socket.onKeyChange(callback);
|
|
510
|
+
}
|
|
462
511
|
async transfer(to, amount, note) {
|
|
463
512
|
return this.$post("/me/transfer", { to, amount, note });
|
|
464
513
|
}
|
|
@@ -932,22 +981,6 @@ var CosmeticsNamespace = class extends Namespace {
|
|
|
932
981
|
async overlays(filepath) {
|
|
933
982
|
return this.$get(`/cosmetics/overlays/${filepath}`, void 0, false);
|
|
934
983
|
}
|
|
935
|
-
/** Admin: List all cosmetics in catalog */
|
|
936
|
-
async adminList(options) {
|
|
937
|
-
return this.$get("/cosmetics/admin/list", options, true);
|
|
938
|
-
}
|
|
939
|
-
/** Admin: Create a cosmetic */
|
|
940
|
-
async adminCreate(data) {
|
|
941
|
-
return this.$post("/cosmetics/admin/create", data);
|
|
942
|
-
}
|
|
943
|
-
/** Admin: Update a cosmetic */
|
|
944
|
-
async adminUpdate(id, data) {
|
|
945
|
-
return this.$patch(`/cosmetics/admin/update/${id}`, data);
|
|
946
|
-
}
|
|
947
|
-
/** Admin: Delete a cosmetic */
|
|
948
|
-
async adminDelete(id) {
|
|
949
|
-
return this.$del(`/cosmetics/admin/delete/${id}`);
|
|
950
|
-
}
|
|
951
984
|
};
|
|
952
985
|
var PushNamespace = class extends Namespace {
|
|
953
986
|
async vapidKeys() {
|
package/dist/index.mjs
CHANGED
|
@@ -109,6 +109,8 @@ var RoturSocket = class extends EventTarget {
|
|
|
109
109
|
_username = null;
|
|
110
110
|
handlers = /* @__PURE__ */ new Map();
|
|
111
111
|
rooms = /* @__PURE__ */ new Set();
|
|
112
|
+
keyCache = {};
|
|
113
|
+
keyChangeCallbacks = /* @__PURE__ */ new Set();
|
|
112
114
|
get connected() {
|
|
113
115
|
return this._connected;
|
|
114
116
|
}
|
|
@@ -121,6 +123,27 @@ var RoturSocket = class extends EventTarget {
|
|
|
121
123
|
get joinedRooms() {
|
|
122
124
|
return [...this.rooms];
|
|
123
125
|
}
|
|
126
|
+
getKey(key) {
|
|
127
|
+
return this.keyCache[key];
|
|
128
|
+
}
|
|
129
|
+
getAllKeys() {
|
|
130
|
+
return { ...this.keyCache };
|
|
131
|
+
}
|
|
132
|
+
onKeyChange(callback) {
|
|
133
|
+
this.keyChangeCallbacks.add(callback);
|
|
134
|
+
return () => this.keyChangeCallbacks.delete(callback);
|
|
135
|
+
}
|
|
136
|
+
offKeyChange(callback) {
|
|
137
|
+
this.keyChangeCallbacks.delete(callback);
|
|
138
|
+
}
|
|
139
|
+
notifyKeyChange(key, value, oldValue) {
|
|
140
|
+
for (const cb of this.keyChangeCallbacks) {
|
|
141
|
+
try {
|
|
142
|
+
cb(key, value, oldValue);
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
124
147
|
connect(token) {
|
|
125
148
|
this.token = token;
|
|
126
149
|
return new Promise((resolve, reject) => {
|
|
@@ -138,11 +161,19 @@ var RoturSocket = class extends EventTarget {
|
|
|
138
161
|
this._connected = true;
|
|
139
162
|
this._userId = msg.user_id;
|
|
140
163
|
this._username = msg.username;
|
|
164
|
+
if (msg.user && typeof msg.user === "object") {
|
|
165
|
+
this.keyCache = { ...msg.user };
|
|
166
|
+
}
|
|
141
167
|
this.startHeartbeat();
|
|
142
168
|
resolve(msg);
|
|
143
169
|
}
|
|
144
170
|
if (cmd === "join_ok") this.rooms.add(msg.room);
|
|
145
171
|
if (cmd === "leave_ok") this.rooms.delete(msg.room);
|
|
172
|
+
if (cmd === "key_update" && typeof msg.key === "string") {
|
|
173
|
+
const old = this.keyCache[msg.key];
|
|
174
|
+
this.keyCache[msg.key] = msg.value;
|
|
175
|
+
this.notifyKeyChange(msg.key, msg.value, old);
|
|
176
|
+
}
|
|
146
177
|
this.emit(cmd, msg);
|
|
147
178
|
};
|
|
148
179
|
this.ws.onerror = (e) => {
|
|
@@ -218,11 +249,8 @@ var RoturSocket = class extends EventTarget {
|
|
|
218
249
|
roomState(room) {
|
|
219
250
|
this.send({ cmd: "room_state", room });
|
|
220
251
|
}
|
|
221
|
-
|
|
222
|
-
this.send({ cmd: "set_status", presence });
|
|
223
|
-
}
|
|
224
|
-
setStatus(status) {
|
|
225
|
-
this.send({ cmd: "set_status", status });
|
|
252
|
+
setStatus(status, presence) {
|
|
253
|
+
this.send({ cmd: "set_status", status, presence });
|
|
226
254
|
}
|
|
227
255
|
addActivity(activity) {
|
|
228
256
|
this.send({ cmd: "add_activity", ...activity });
|
|
@@ -256,6 +284,7 @@ var RoturSocket = class extends EventTarget {
|
|
|
256
284
|
this.token = null;
|
|
257
285
|
this.cleanup();
|
|
258
286
|
this.rooms.clear();
|
|
287
|
+
this.keyCache = {};
|
|
259
288
|
if (this.ws) {
|
|
260
289
|
this.ws.onclose = null;
|
|
261
290
|
this.ws.close();
|
|
@@ -353,6 +382,9 @@ var Rotur = class {
|
|
|
353
382
|
this._token = options?.token ?? null;
|
|
354
383
|
this._http = new Http(() => this._token);
|
|
355
384
|
this.socket = new RoturSocket(options?.wsUrl);
|
|
385
|
+
if (this._token) {
|
|
386
|
+
this._socketReady = this.socket.connect(this._token).catch(() => null);
|
|
387
|
+
}
|
|
356
388
|
}
|
|
357
389
|
get token() {
|
|
358
390
|
return this._token;
|
|
@@ -362,18 +394,26 @@ var Rotur = class {
|
|
|
362
394
|
}
|
|
363
395
|
setToken(token) {
|
|
364
396
|
this._token = token;
|
|
397
|
+
if (!this.socket.connected) {
|
|
398
|
+
this._socketReady = this.socket.connect(this._token).catch(() => null);
|
|
399
|
+
}
|
|
365
400
|
}
|
|
401
|
+
_socketReady = null;
|
|
366
402
|
async login(options) {
|
|
367
403
|
const { token } = await performAuth(options);
|
|
368
404
|
this._token = token;
|
|
405
|
+
this._socketReady = this.socket.connect(this._token).catch(() => null);
|
|
369
406
|
return this;
|
|
370
407
|
}
|
|
371
408
|
async connectSocket() {
|
|
372
409
|
if (!this._token) throw new ApiError(401, { error: "Login first" });
|
|
373
|
-
|
|
410
|
+
const result = await this.socket.connect(this._token);
|
|
411
|
+
this._socketReady = Promise.resolve(result);
|
|
412
|
+
return result;
|
|
374
413
|
}
|
|
375
414
|
logout() {
|
|
376
415
|
this._token = null;
|
|
416
|
+
this._socketReady = null;
|
|
377
417
|
this.socket.disconnect();
|
|
378
418
|
}
|
|
379
419
|
};
|
|
@@ -429,6 +469,15 @@ var MeNamespace = class extends Namespace {
|
|
|
429
469
|
async refreshToken() {
|
|
430
470
|
return this.$post("/me/refresh_token");
|
|
431
471
|
}
|
|
472
|
+
getKey(key) {
|
|
473
|
+
return this.r.socket.getKey(key);
|
|
474
|
+
}
|
|
475
|
+
getAllKeys() {
|
|
476
|
+
return this.r.socket.getAllKeys();
|
|
477
|
+
}
|
|
478
|
+
onKeyChange(callback) {
|
|
479
|
+
return this.r.socket.onKeyChange(callback);
|
|
480
|
+
}
|
|
432
481
|
async transfer(to, amount, note) {
|
|
433
482
|
return this.$post("/me/transfer", { to, amount, note });
|
|
434
483
|
}
|
|
@@ -902,22 +951,6 @@ var CosmeticsNamespace = class extends Namespace {
|
|
|
902
951
|
async overlays(filepath) {
|
|
903
952
|
return this.$get(`/cosmetics/overlays/${filepath}`, void 0, false);
|
|
904
953
|
}
|
|
905
|
-
/** Admin: List all cosmetics in catalog */
|
|
906
|
-
async adminList(options) {
|
|
907
|
-
return this.$get("/cosmetics/admin/list", options, true);
|
|
908
|
-
}
|
|
909
|
-
/** Admin: Create a cosmetic */
|
|
910
|
-
async adminCreate(data) {
|
|
911
|
-
return this.$post("/cosmetics/admin/create", data);
|
|
912
|
-
}
|
|
913
|
-
/** Admin: Update a cosmetic */
|
|
914
|
-
async adminUpdate(id, data) {
|
|
915
|
-
return this.$patch(`/cosmetics/admin/update/${id}`, data);
|
|
916
|
-
}
|
|
917
|
-
/** Admin: Delete a cosmetic */
|
|
918
|
-
async adminDelete(id) {
|
|
919
|
-
return this.$del(`/cosmetics/admin/delete/${id}`);
|
|
920
|
-
}
|
|
921
954
|
};
|
|
922
955
|
var PushNamespace = class extends Namespace {
|
|
923
956
|
async vapidKeys() {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rotur-sdk",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "The official SDK for the Rotur platform
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "The official SDK for the Rotur platform - auth, profiles, posts, credits, keys, groups, items, gifts, tokens, validators, status, files, cosmetics, push notifications, and more",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|