@anvil-js/client 0.0.1

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.
@@ -0,0 +1,298 @@
1
+ interface Packet {
2
+ type: string;
3
+ id: string;
4
+ payload: any;
5
+ }
6
+ declare class ConnectionCodec {
7
+ /** typeId → packetName (frames we receive) */
8
+ private incoming;
9
+ /** packetName → typeId (frames we send) */
10
+ private outgoing;
11
+ private nextOutgoingTypeId;
12
+ constructor();
13
+ /**
14
+ * Decode a single binary frame. Returns null for registration
15
+ * frames (which mutate the codec in place) and for unknown
16
+ * typeIds.
17
+ */
18
+ decode(buffer: ArrayBuffer | Uint8Array): Packet | null;
19
+ /**
20
+ * Encode a packet to a binary frame. If the packet name has
21
+ * not been registered yet, a fresh typeId is allocated and
22
+ * a registration frame is yielded first.
23
+ */
24
+ encode(name: string, payload: any, id?: string): Uint8Array[];
25
+ /** Register a packet type up-front (returns the typeId assigned). */
26
+ registerOutgoing(name: string): number;
27
+ }
28
+
29
+ /**
30
+ * Anvil WebSocket client -- speaks the Essential Mod binary
31
+ * protocol over a single WebSocket connection.
32
+ *
33
+ * High-level API is a thin wrapper around the codec: every
34
+ * Essential Mod packet type has a corresponding `send*` method
35
+ * that returns a Promise resolving with the response packet
36
+ * (matched by packet id).
37
+ *
38
+ * Plus a typed event emitter for server-initiated packets
39
+ * (chat messages, friend status changes, profile updates, etc.)
40
+ * so React components can subscribe to live state.
41
+ */
42
+
43
+ interface AnvilWsConfig {
44
+ /** WebSocket URL, e.g. "ws://localhost:3001/v1" */
45
+ url: string;
46
+ /** User UUID (sent as `essential-user-uuid` header). */
47
+ userUuid: string;
48
+ /** Username (sent as `essential-user-name` header). */
49
+ userName: string;
50
+ /** Max protocol version we understand. Default: 9. */
51
+ maxProtocolVersion?: number;
52
+ /** Authentication token (sent as `essential-authentication-token`). */
53
+ authenticationToken?: string;
54
+ /** Auto-reconnect on close. Default: true. */
55
+ autoReconnect?: boolean;
56
+ /** Reconnect delay in ms. Default: 2000. */
57
+ reconnectDelayMs?: number;
58
+ }
59
+ interface ChatMessage {
60
+ id: number;
61
+ channelId: number;
62
+ senderUuid: string;
63
+ content: string;
64
+ replyToId: number | null;
65
+ editedAt: number | null;
66
+ deleted: boolean;
67
+ createdAt: number;
68
+ }
69
+ interface ProfileStatus {
70
+ uuid: string;
71
+ status: 'ONLINE' | 'OFFLINE' | 'AWAY' | 'BUSY';
72
+ lastOnlineTimestamp: number;
73
+ }
74
+ interface FriendRelationship {
75
+ userA: string;
76
+ userB: string;
77
+ type: 'FRIENDS' | 'BLOCKED' | 'NEUTRAL';
78
+ status: 'PENDING' | 'VERIFIED';
79
+ since: number;
80
+ }
81
+ interface AnvilWsEvents {
82
+ open: void;
83
+ close: {
84
+ code: number;
85
+ reason: string;
86
+ };
87
+ error: Error;
88
+ bootstrap: void;
89
+ chat: ChatMessage & {
90
+ channelId: number;
91
+ };
92
+ friendAdded: FriendRelationship;
93
+ friendRemoved: {
94
+ userA: string;
95
+ userB: string;
96
+ type: string;
97
+ };
98
+ profileStatus: ProfileStatus;
99
+ profileActivity: {
100
+ uuid: string;
101
+ activity: string;
102
+ metadata: any;
103
+ };
104
+ cosmeticAnimation: {
105
+ userUuid: string;
106
+ cosmeticId: string;
107
+ animationId: string;
108
+ };
109
+ notice: {
110
+ id: string;
111
+ title: string;
112
+ body: string;
113
+ category: string;
114
+ };
115
+ serverList: {
116
+ recommended: any[];
117
+ featured: any[];
118
+ };
119
+ cosmeticsUnlocked: {
120
+ userUuid: string;
121
+ unlockedIds: string[];
122
+ gifted: boolean;
123
+ unlockMap: Record<string, any>;
124
+ };
125
+ equippedUpdate: {
126
+ userUuid: string;
127
+ equipped: Record<string, string>;
128
+ };
129
+ playerSettings: {
130
+ userUuid: string;
131
+ settings: Record<string, any>;
132
+ };
133
+ skinTexture: {
134
+ userUuid: string;
135
+ skinTexture: string | null;
136
+ };
137
+ upnpSession: {
138
+ hostUuid: string;
139
+ ip: string;
140
+ port: number;
141
+ privacy: string;
142
+ worldName: string | null;
143
+ protocolVersion: number | null;
144
+ invites: string[];
145
+ createdAt: number;
146
+ rawStatus: string | null;
147
+ };
148
+ upnpSessionRemoved: {
149
+ hostUuid: string;
150
+ };
151
+ upnpInvite: {
152
+ hostUuid: string;
153
+ };
154
+ raw: Packet;
155
+ }
156
+ type Listener<T> = (data: T) => void;
157
+ declare class AnvilWsClient {
158
+ private ws;
159
+ private codec;
160
+ private config;
161
+ private listeners;
162
+ private pendingRequests;
163
+ private state;
164
+ private bootstrapReceived;
165
+ private reconnectTimer;
166
+ private defaultRequestTimeoutMs;
167
+ constructor(config: AnvilWsConfig);
168
+ connect(): Promise<void>;
169
+ disconnect(): void;
170
+ private scheduleReconnect;
171
+ private preRegisterOutgoing;
172
+ private handleFrame;
173
+ private dispatch;
174
+ private sendRequest;
175
+ sendChatMessage(channelId: number, content: string, replyToId?: number): Promise<Packet & {
176
+ payload: any;
177
+ }>;
178
+ retrieveChatMessages(channelId: number, limit?: number, beforeMessageId?: number): Promise<Packet & {
179
+ payload: any;
180
+ }>;
181
+ createChannel(type: 'DIRECT_MESSAGE' | 'GROUP_DIRECT_MESSAGE' | 'ANNOUNCEMENT', name: string, memberUuids?: string[]): Promise<Packet & {
182
+ payload: any;
183
+ }>;
184
+ deleteChatMessage(messageId: number): Promise<Packet & {
185
+ payload: any;
186
+ }>;
187
+ addFriend(targetUuid: string): Promise<Packet & {
188
+ payload: any;
189
+ }>;
190
+ removeFriend(targetUuid: string): Promise<Packet & {
191
+ payload: any;
192
+ }>;
193
+ blockUser(targetUuid: string): Promise<Packet & {
194
+ payload: any;
195
+ }>;
196
+ lookupUuidByName(username: string): Promise<Packet & {
197
+ payload: any;
198
+ }>;
199
+ getProfile(uuid: string): Promise<Packet & {
200
+ payload: any;
201
+ }>;
202
+ setActivity(activity: string, metadata?: any): Promise<Packet & {
203
+ payload: any;
204
+ }>;
205
+ listCosmetics(): Promise<Packet & {
206
+ payload: any;
207
+ }>;
208
+ triggerCosmeticAnimation(cosmeticId: string, animationId: string): Promise<Packet & {
209
+ payload: any;
210
+ }>;
211
+ unlockCosmetics(cosmeticIds: string[]): Promise<Packet & {
212
+ payload: any;
213
+ }>;
214
+ createSkin(name: string, model: 'CLASSIC' | 'SLIM', hash: string): Promise<Packet & {
215
+ payload: any;
216
+ }>;
217
+ selectLastUsedSkin(skinId: string): Promise<Packet & {
218
+ payload: any;
219
+ }>;
220
+ favoriteSkin(skinId: string, favorited: boolean): Promise<Packet & {
221
+ payload: any;
222
+ }>;
223
+ createOutfit(name: string, equippedCosmetics: Record<string, string>, settings?: Record<string, any>): Promise<Packet & {
224
+ payload: any;
225
+ }>;
226
+ selectOutfit(outfitId: string): Promise<Packet & {
227
+ payload: any;
228
+ }>;
229
+ setEquippedCosmetic(outfitId: string, slot: string, cosmeticId: string): Promise<Packet & {
230
+ payload: any;
231
+ }>;
232
+ updateEmoteWheel(wheelId: string, slots: Record<string, string>): Promise<Packet & {
233
+ payload: any;
234
+ }>;
235
+ selectEmoteWheel(wheelId: string): Promise<Packet & {
236
+ payload: any;
237
+ }>;
238
+ getWardrobeSettings(): Promise<Packet & {
239
+ payload: any;
240
+ }>;
241
+ listNotices(): Promise<Packet & {
242
+ payload: any;
243
+ }>;
244
+ listServerDiscovery(): Promise<Packet & {
245
+ payload: any;
246
+ }>;
247
+ listKnownServers(): Promise<Packet & {
248
+ payload: any;
249
+ }>;
250
+ relayIcePacket(targetUuid: string, payload: Uint8Array): Promise<Packet & {
251
+ payload: any;
252
+ }>;
253
+ pingServer(host: string, port: number, protocolVersion?: number): Promise<Packet & {
254
+ payload: any;
255
+ }>;
256
+ createSession(ip: string, port: number, privacy: 'PUBLIC' | 'FRIENDS' | 'INVITE_ONLY', worldName?: string, protocolVersion?: number): Promise<Packet & {
257
+ payload: any;
258
+ }>;
259
+ closeSession(): Promise<Packet & {
260
+ payload: any;
261
+ }>;
262
+ updateSession(patch: {
263
+ ip?: string;
264
+ port?: number;
265
+ privacy?: 'PUBLIC' | 'FRIENDS' | 'INVITE_ONLY';
266
+ }): Promise<Packet & {
267
+ payload: any;
268
+ }>;
269
+ inviteToSession(inviteeUuids: string[]): Promise<Packet & {
270
+ payload: any;
271
+ }>;
272
+ revokeSessionInvites(inviteeUuids: string[]): Promise<Packet & {
273
+ payload: any;
274
+ }>;
275
+ pushServerStatus(rawStatus: string): Promise<Packet & {
276
+ payload: any;
277
+ }>;
278
+ inviteFriendToServer(targetUuid: string, address: string): Promise<Packet & {
279
+ payload: any;
280
+ }>;
281
+ on<K extends keyof AnvilWsEvents>(event: K, listener: Listener<AnvilWsEvents[K]>): () => void;
282
+ off<K extends keyof AnvilWsEvents>(event: K, listener: Listener<AnvilWsEvents[K]>): void;
283
+ private emit;
284
+ isReady(): boolean;
285
+ isConnected(): boolean;
286
+ }
287
+ /**
288
+ * Subscribe to a WS event in a React component. The subscription
289
+ * is cleaned up automatically on unmount.
290
+ */
291
+ declare function useWsEvent<K extends keyof AnvilWsEvents>(client: AnvilWsClient, event: K, handler: Listener<AnvilWsEvents[K]>): void;
292
+ /**
293
+ * Track connection state for a WS client. Returns the current
294
+ * state ('disconnected' | 'connecting' | 'connected' | 'ready').
295
+ */
296
+ declare function useWsState(client: AnvilWsClient): AnvilWsClient['state'] | 'disconnected';
297
+
298
+ export { AnvilWsClient, type AnvilWsConfig, type AnvilWsEvents, type ChatMessage, ConnectionCodec, type FriendRelationship, type Packet, type ProfileStatus, useWsEvent, useWsState };