@anvil-js/client 0.0.1 → 0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ws/codec.ts","../../src/ws/client.ts"],"names":["uuidv4","useEffect","useState"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Binary codec for the Essential Mod WebSocket protocol.\n *\n * Wire format (big-endian, per frame):\n * [int32 typeId][int32 idLen][utf8 packetId][int32 payloadLen][utf8 payloadJson]\n *\n * `typeId = 0` is the registration frame: `{ a: packetName, b: typeId }`\n * -- both directions exchange these on connect to learn each other's\n * dynamic typeId → packetName mapping.\n */\nimport { v4 as uuidv4 } from 'uuid';\n\nexport interface Packet {\n type: string;\n id: string;\n payload: any;\n}\n\nexport class ConnectionCodec {\n /** typeId → packetName (frames we receive) */\n private incoming = new Map<number, string>();\n /** packetName → typeId (frames we send) */\n private outgoing = new Map<string, number>();\n private nextOutgoingTypeId = 100;\n\n constructor() {\n // The registration frame is always typeId 0 in both directions.\n this.incoming.set(0, 'connection.ConnectionRegisterPacketTypeIdPacket');\n this.outgoing.set('connection.ConnectionRegisterPacketTypeIdPacket', 0);\n }\n\n /**\n * Decode a single binary frame. Returns null for registration\n * frames (which mutate the codec in place) and for unknown\n * typeIds.\n */\n decode(buffer: ArrayBuffer | Uint8Array): Packet | null {\n const view = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n if (view.byteLength < 4) return null;\n const dv = new DataView(view.buffer, view.byteOffset, view.byteLength);\n let off = 0;\n\n const typeId = dv.getInt32(off);\n off += 4;\n const name = this.incoming.get(typeId);\n if (!name) return null;\n\n const idLen = dv.getInt32(off);\n off += 4;\n const id = new TextDecoder('utf-8').decode(view.subarray(off, off + idLen));\n off += idLen;\n\n const payloadLen = dv.getInt32(off);\n off += 4;\n const payloadJson = new TextDecoder('utf-8').decode(view.subarray(off, off + payloadLen));\n\n if (name === 'connection.ConnectionRegisterPacketTypeIdPacket') {\n const reg = JSON.parse(payloadJson);\n this.incoming.set(reg.b, reg.a);\n return null;\n }\n return { type: name, id, payload: JSON.parse(payloadJson) };\n }\n\n /**\n * Encode a packet to a binary frame. If the packet name has\n * not been registered yet, a fresh typeId is allocated and\n * a registration frame is yielded first.\n */\n encode(name: string, payload: any, id: string = uuidv4()): Uint8Array[] {\n const frames: Uint8Array[] = [];\n\n if (!this.outgoing.has(name)) {\n this.outgoing.set(name, this.nextOutgoingTypeId++);\n // First time we send this type, prepend a registration frame\n // so the server learns our typeId.\n frames.push(\n ...this.encode(\n 'connection.ConnectionRegisterPacketTypeIdPacket',\n { a: name, b: this.outgoing.get(name) },\n '',\n ),\n );\n }\n const typeId = this.outgoing.get(name)!;\n const payloadBytes = new TextEncoder().encode(JSON.stringify(payload));\n const idBytes = id ? new TextEncoder().encode(id) : new Uint8Array(0);\n\n const total = 4 + 4 + idBytes.length + 4 + payloadBytes.length;\n const buf = new Uint8Array(total);\n const dv = new DataView(buf.buffer);\n let off = 0;\n dv.setInt32(off, typeId);\n off += 4;\n dv.setInt32(off, idBytes.length);\n off += 4;\n buf.set(idBytes, off);\n off += idBytes.length;\n dv.setInt32(off, payloadBytes.length);\n off += 4;\n buf.set(payloadBytes, off);\n\n frames.push(buf);\n return frames;\n }\n\n /** Register a packet type up-front (returns the typeId assigned). */\n registerOutgoing(name: string): number {\n if (!this.outgoing.has(name)) {\n this.outgoing.set(name, this.nextOutgoingTypeId++);\n }\n return this.outgoing.get(name)!;\n }\n}\n","/**\n * Anvil WebSocket client -- speaks the Essential Mod binary\n * protocol over a single WebSocket connection.\n *\n * High-level API is a thin wrapper around the codec: every\n * Essential Mod packet type has a corresponding `send*` method\n * that returns a Promise resolving with the response packet\n * (matched by packet id).\n *\n * Plus a typed event emitter for server-initiated packets\n * (chat messages, friend status changes, profile updates, etc.)\n * so React components can subscribe to live state.\n */\nimport { ConnectionCodec, type Packet } from './codec';\n\nexport interface AnvilWsConfig {\n /** WebSocket URL, e.g. \"ws://localhost:3001/v1\" */\n url: string;\n /** User UUID (sent as `essential-user-uuid` header). */\n userUuid: string;\n /** Username (sent as `essential-user-name` header). */\n userName: string;\n /** Max protocol version we understand. Default: 9. */\n maxProtocolVersion?: number;\n /** Authentication token (sent as `essential-authentication-token`). */\n authenticationToken?: string;\n /** Auto-reconnect on close. Default: true. */\n autoReconnect?: boolean;\n /** Reconnect delay in ms. Default: 2000. */\n reconnectDelayMs?: number;\n}\n\n// ----- Event payloads -----\n\nexport interface ChatMessage {\n id: number;\n channelId: number;\n senderUuid: string;\n content: string;\n replyToId: number | null;\n editedAt: number | null;\n deleted: boolean;\n createdAt: number;\n}\n\nexport interface ProfileStatus {\n uuid: string;\n status: 'ONLINE' | 'OFFLINE' | 'AWAY' | 'BUSY';\n lastOnlineTimestamp: number;\n}\n\nexport interface FriendRelationship {\n userA: string;\n userB: string;\n type: 'FRIENDS' | 'BLOCKED' | 'NEUTRAL';\n status: 'PENDING' | 'VERIFIED';\n since: number;\n}\n\n// ----- Event map -----\n\nexport interface AnvilWsEvents {\n open: void;\n close: { code: number; reason: string };\n error: Error;\n bootstrap: void;\n chat: ChatMessage & { channelId: number };\n friendAdded: FriendRelationship;\n friendRemoved: { userA: string; userB: string; type: string };\n profileStatus: ProfileStatus;\n profileActivity: { uuid: string; activity: string; metadata: any };\n cosmeticAnimation: { userUuid: string; cosmeticId: string; animationId: string };\n notice: { id: string; title: string; body: string; category: string };\n serverList: { recommended: any[]; featured: any[] };\n cosmeticsUnlocked: {\n userUuid: string;\n unlockedIds: string[];\n gifted: boolean;\n unlockMap: Record<string, any>;\n };\n equippedUpdate: { userUuid: string; equipped: Record<string, string> };\n playerSettings: { userUuid: string; settings: Record<string, any> };\n skinTexture: { userUuid: string; skinTexture: string | null };\n upnpSession: {\n hostUuid: string;\n ip: string;\n port: number;\n privacy: string;\n worldName: string | null;\n protocolVersion: number | null;\n invites: string[];\n createdAt: number;\n rawStatus: string | null;\n };\n upnpSessionRemoved: { hostUuid: string };\n upnpInvite: { hostUuid: string };\n raw: Packet;\n}\n\ntype Listener<T> = (data: T) => void;\n\n// ----- Client -----\n\nexport class AnvilWsClient {\n private ws: WebSocket | null = null;\n private codec = new ConnectionCodec();\n private config: Required<AnvilWsConfig>;\n private listeners = new Map<keyof AnvilWsEvents, Set<Listener<any>>>();\n private pendingRequests = new Map<\n string,\n {\n resolve: (p: Packet) => void;\n reject: (e: Error) => void;\n type: string;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n private state: 'disconnected' | 'connecting' | 'connected' | 'ready' = 'disconnected';\n private bootstrapReceived = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private defaultRequestTimeoutMs = 10_000;\n\n constructor(config: AnvilWsConfig) {\n this.config = {\n maxProtocolVersion: 9,\n autoReconnect: true,\n reconnectDelayMs: 2000,\n authenticationToken: '',\n ...config,\n };\n }\n\n // ----- Lifecycle -----\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.state === 'ready' || this.state === 'connected') {\n resolve();\n return;\n }\n this.state = 'connecting';\n\n const params = new URLSearchParams();\n params.set('essential-user-uuid', this.config.userUuid);\n params.set('essential-user-name', this.config.userName);\n params.set('essential-max-protocol-version', String(this.config.maxProtocolVersion));\n if (this.config.authenticationToken) {\n params.set('essential-authentication-token', this.config.authenticationToken);\n }\n const url = `${this.config.url}?${params.toString()}`;\n\n this.ws = new WebSocket(url);\n this.ws.binaryType = 'arraybuffer';\n\n this.ws.onopen = () => {\n this.state = 'connected';\n this.emit('open', undefined as any);\n // Pre-register the full client packet vocabulary so\n // the server can route every request type we might send.\n this.preRegisterOutgoing();\n resolve();\n };\n\n this.ws.onerror = (e) => {\n this.emit('error', new Error('WebSocket error'));\n reject(new Error('WebSocket error'));\n };\n\n this.ws.onclose = (ev) => {\n this.state = 'disconnected';\n this.emit('close', { code: ev.code, reason: ev.reason });\n // Reject all pending requests\n for (const [, req] of this.pendingRequests) {\n clearTimeout(req.timer);\n req.reject(new Error('Connection closed'));\n }\n this.pendingRequests.clear();\n if (this.config.autoReconnect && this.bootstrapReceived) {\n this.scheduleReconnect();\n }\n };\n\n this.ws.onmessage = (ev) => {\n this.handleFrame(ev.data as ArrayBuffer);\n };\n });\n }\n\n disconnect(): void {\n this.config.autoReconnect = false;\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n if (this.ws) {\n this.ws.close(1000, 'Client disconnect');\n this.ws = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) return;\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect().catch(() => {\n /* will retry via close handler */\n });\n }, this.config.reconnectDelayMs);\n }\n\n private preRegisterOutgoing(): void {\n // All client packet types we might send. The codec will\n // emit a registration frame for each one the first time\n // it's used; pre-registering here keeps the wire clean.\n const TYPES = [\n 'chat.ClientChatChannelMessageCreatePacket',\n 'chat.ClientChatChannelMessagesRetrievePacket',\n 'chat.ClientChatChannelCreatePacket',\n 'chat.ClientChatChannelMessageUpdatePacket',\n 'chat.ChatChannelMessageDeletePacket',\n 'chat.ClientChatChannelMessageReportPacket',\n 'chat.ChatChannelMemberAddPacket',\n 'chat.ChatChannelMemberRemovePacket',\n 'chat.ClientChatChannelMutePacket',\n 'chat.ClientChatChannelReadStatePacket',\n 'chat.ClientChatChannelMessageReadStatePacket',\n 'relationships.ClientRelationshipCreatePacket',\n 'relationships.RelationshipDeletePacket',\n 'relationships.ClientLookupUuidByNamePacket',\n 'profile.ClientProfileRequestPacket',\n 'profile.ClientProfileActivityPacket',\n 'cosmetic.ClientCosmeticRequestPacket',\n 'cosmetic.ClientCosmeticBulkRequestUnlockStatePacket',\n 'cosmetic.ClientCosmeticAnimationTriggerPacket',\n 'skin.ClientSkinCreatePacket',\n 'skin.ClientSkinUpdateLastUsedStatePacket',\n 'skin.ClientSkinUpdateFavoriteStatePacket',\n 'skin.ClientSelectedSkinsRequestPacket',\n 'cosmetic.outfit.ClientCosmeticOutfitCreatePacket',\n 'cosmetic.outfit.ClientCosmeticOutfitSelectPacket',\n 'cosmetic.outfit.ClientCosmeticOutfitEquippedCosmeticsUpdatePacket',\n 'cosmetic.emote.ClientCosmeticEmoteWheelUpdatePacket',\n 'cosmetic.emote.ClientCosmeticEmoteWheelSelectPacket',\n 'wardrobe.ClientWardrobeSettingsPacket',\n 'checkout.ClientCheckoutCosmeticsPacket',\n 'coins.ClientCoinsBalancePacket',\n 'notices.ClientNoticeRequestPacket',\n 'serverdiscovery.ClientServerDiscoveryRequestPacket',\n 'knownservers.ClientKnownServersRequestPacket',\n 'multiplayer.ClientMultiplayerIceRelayPacket',\n 'pingproxy.ClientPingProxyRequestPacket',\n 'social.ClientCommunityRulesAgreedPacket',\n ];\n for (const t of TYPES) this.codec.registerOutgoing(t);\n }\n\n // ----- Frame handling -----\n\n private handleFrame(data: ArrayBuffer): void {\n const packet = this.codec.decode(data);\n if (!packet) return;\n this.emit('raw', packet);\n this.dispatch(packet);\n }\n\n private dispatch(packet: Packet): void {\n // Resolve pending request if this is a response (matched by id)\n if (packet.id && this.pendingRequests.has(packet.id)) {\n const req = this.pendingRequests.get(packet.id)!;\n this.pendingRequests.delete(packet.id);\n clearTimeout(req.timer);\n req.resolve(packet);\n return;\n }\n\n // Bootstrap complete?\n if (!this.bootstrapReceived && packet.type === 'social.ServerCommunityRulesStatePacket') {\n this.bootstrapReceived = true;\n this.state = 'ready';\n this.emit('bootstrap', undefined as any);\n }\n\n // Server-pushed events\n switch (packet.type) {\n case 'chat.ServerChatChannelMessagePacket': {\n const msgs: any[] = packet.payload.a || [];\n for (const m of msgs) {\n this.emit('chat', {\n id: m.a,\n channelId: m.b ?? 0,\n senderUuid: m.c,\n content: m.d,\n replyToId: m.e ?? null,\n editedAt: m.f ?? null,\n deleted: m.g ?? false,\n createdAt: m.h ?? Date.now(),\n });\n }\n break;\n }\n case 'relationships.ServerRelationshipPopulatePacket': {\n const rels: any[] = packet.payload.a || [];\n for (const r of rels) {\n this.emit('friendAdded', {\n userA: r.a,\n userB: r.b,\n type: r.c,\n status: r.d,\n since: r.e,\n });\n }\n break;\n }\n case 'relationships.ServerRelationshipDeletedPacket': {\n const dels: any[] = packet.payload.a || [];\n for (const d of dels) {\n this.emit('friendRemoved', { userA: d.a, userB: d.b, type: d.c });\n }\n break;\n }\n case 'profile.ServerProfileStatusPacket': {\n this.emit('profileStatus', {\n uuid: packet.payload.a,\n status: packet.payload.b,\n lastOnlineTimestamp: packet.payload.lastOnlineTimestamp ?? 0,\n });\n break;\n }\n case 'profile.ServerProfileActivityPacket': {\n this.emit('profileActivity', {\n uuid: packet.payload.a,\n activity: packet.payload.b,\n metadata: packet.payload.c,\n });\n break;\n }\n case 'cosmetic.ServerCosmeticAnimationTriggerPacket': {\n this.emit('cosmeticAnimation', {\n userUuid: packet.payload.a,\n cosmeticId: packet.payload.b,\n animationId: packet.payload.c,\n });\n break;\n }\n case 'notices.ServerNoticePopulatePacket': {\n const items: any[] = packet.payload.items || packet.payload.a || [];\n for (const n of items) {\n this.emit('notice', { id: n.a, title: n.b, body: n.c, category: n.d });\n }\n break;\n }\n case 'cosmetic.ServerCosmeticsUserUnlockedPacket': {\n this.emit('cosmeticsUnlocked', {\n userUuid: packet.payload.c,\n unlockedIds: packet.payload.a ?? [],\n gifted: packet.payload.b,\n unlockMap: packet.payload.d ?? {},\n });\n break;\n }\n case 'cosmetic.ServerCosmeticsUserEquippedPacket': {\n this.emit('equippedUpdate', {\n userUuid: packet.payload.a,\n equipped: packet.payload.b,\n });\n break;\n }\n case 'cosmetic.ServerCosmeticPlayerSettingsPacket': {\n this.emit('playerSettings', {\n userUuid: packet.payload.a,\n settings: packet.payload.b,\n });\n break;\n }\n case 'cosmetic.ServerCosmeticsSkinTexturePacket': {\n this.emit('skinTexture', {\n userUuid: packet.payload.a,\n skinTexture: packet.payload.b,\n });\n break;\n }\n case 'upnp.ServerUPnPSessionPopulatePacket': {\n const sessions: any[] = packet.payload.a || [];\n for (const s of sessions) {\n this.emit('upnpSession', {\n hostUuid: s.a,\n ip: s.b,\n port: s.c,\n privacy: s.d,\n worldName: s.e,\n protocolVersion: s.f,\n invites: s.g ?? [],\n createdAt: s.h,\n rawStatus: s.i,\n });\n }\n break;\n }\n case 'upnp.ServerUPnPSessionRemovePacket': {\n const removed: string[] = packet.payload.a || [];\n for (const hostUuid of removed) {\n this.emit('upnpSessionRemoved', { hostUuid });\n }\n break;\n }\n case 'upnp.ServerUPnPSessionInviteAddPacket': {\n this.emit('upnpInvite', { hostUuid: packet.payload.a });\n break;\n }\n case 'serverdiscovery.ServerServerDiscoveryResponsePacket': {\n this.emit('serverList', {\n recommended: packet.payload.recommended || [],\n featured: packet.payload.featured || [],\n });\n break;\n }\n }\n }\n\n // ----- Request/response -----\n\n private sendRequest<T = any>(\n type: string,\n payload: any,\n timeoutMs = this.defaultRequestTimeoutMs,\n ): Promise<Packet & { payload: T }> {\n return new Promise((resolve, reject) => {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n reject(new Error('WebSocket not connected'));\n return;\n }\n const id = crypto.randomUUID();\n const timer = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`Request ${type} timed out`));\n }, timeoutMs);\n this.pendingRequests.set(id, { resolve: resolve as any, reject, type, timer });\n for (const frame of this.codec.encode(type, payload, id)) {\n this.ws.send(frame);\n }\n });\n }\n\n // ----- High-level API -----\n\n // Chat\n sendChatMessage(channelId: number, content: string, replyToId?: number) {\n return this.sendRequest('chat.ClientChatChannelMessageCreatePacket', {\n a: channelId,\n b: content,\n c: replyToId ?? null,\n });\n }\n retrieveChatMessages(channelId: number, limit = 50, beforeMessageId?: number) {\n return this.sendRequest('chat.ClientChatChannelMessagesRetrievePacket', {\n a: channelId,\n b: limit,\n c: beforeMessageId ?? null,\n });\n }\n createChannel(\n type: 'DIRECT_MESSAGE' | 'GROUP_DIRECT_MESSAGE' | 'ANNOUNCEMENT',\n name: string,\n memberUuids: string[] = [],\n ) {\n return this.sendRequest('chat.ClientChatChannelCreatePacket', {\n a: type,\n b: name,\n c: memberUuids,\n });\n }\n deleteChatMessage(messageId: number) {\n return this.sendRequest('chat.ChatChannelMessageDeletePacket', { a: messageId });\n }\n\n // Social\n addFriend(targetUuid: string) {\n return this.sendRequest('relationships.ClientRelationshipCreatePacket', {\n a: targetUuid,\n b: 'FRIENDS',\n });\n }\n removeFriend(targetUuid: string) {\n return this.sendRequest('relationships.RelationshipDeletePacket', {\n a: targetUuid,\n b: 'FRIENDS',\n });\n }\n blockUser(targetUuid: string) {\n return this.sendRequest('relationships.ClientRelationshipCreatePacket', {\n a: targetUuid,\n b: 'BLOCKED',\n });\n }\n lookupUuidByName(username: string) {\n return this.sendRequest('relationships.ClientLookupUuidByNamePacket', { username });\n }\n\n // Profile\n getProfile(uuid: string) {\n return this.sendRequest('profile.ClientProfileRequestPacket', { a: uuid });\n }\n setActivity(activity: string, metadata: any = {}) {\n return this.sendRequest('profile.ClientProfileActivityPacket', { a: activity, c: metadata });\n }\n\n // Cosmetics\n listCosmetics() {\n return this.sendRequest('cosmetic.ClientCosmeticRequestPacket', {});\n }\n triggerCosmeticAnimation(cosmeticId: string, animationId: string) {\n return this.sendRequest('cosmetic.ClientCosmeticAnimationTriggerPacket', {\n a: cosmeticId,\n b: animationId,\n });\n }\n unlockCosmetics(cosmeticIds: string[]) {\n return this.sendRequest('checkout.ClientCheckoutCosmeticsPacket', {\n cosmetic_ids: cosmeticIds,\n });\n }\n\n // Skins\n createSkin(name: string, model: 'CLASSIC' | 'SLIM', hash: string) {\n return this.sendRequest('skin.ClientSkinCreatePacket', { a: name, b: model, c: hash });\n }\n selectLastUsedSkin(skinId: string) {\n return this.sendRequest('skin.ClientSkinUpdateLastUsedStatePacket', { a: skinId });\n }\n favoriteSkin(skinId: string, favorited: boolean) {\n return this.sendRequest('skin.ClientSkinUpdateFavoriteStatePacket', {\n a: skinId,\n b: favorited,\n });\n }\n\n // Outfits\n createOutfit(\n name: string,\n equippedCosmetics: Record<string, string>,\n settings: Record<string, any> = {},\n ) {\n return this.sendRequest('cosmetic.outfit.ClientCosmeticOutfitCreatePacket', {\n name,\n skin_id: null,\n equipped_cosmetics: equippedCosmetics,\n cosmetic_settings: settings,\n });\n }\n selectOutfit(outfitId: string) {\n return this.sendRequest('cosmetic.outfit.ClientCosmeticOutfitSelectPacket', { a: outfitId });\n }\n setEquippedCosmetic(outfitId: string, slot: string, cosmeticId: string) {\n return this.sendRequest('cosmetic.outfit.ClientCosmeticOutfitEquippedCosmeticsUpdatePacket', {\n a: outfitId,\n b: slot,\n c: cosmeticId,\n });\n }\n\n // Emote wheel\n updateEmoteWheel(wheelId: string, slots: Record<string, string>) {\n return this.sendRequest('cosmetic.emote.ClientCosmeticEmoteWheelUpdatePacket', {\n a: wheelId,\n b: slots,\n });\n }\n selectEmoteWheel(wheelId: string) {\n return this.sendRequest('cosmetic.emote.ClientCosmeticEmoteWheelSelectPacket', { a: wheelId });\n }\n\n // Wardrobe settings\n getWardrobeSettings() {\n return this.sendRequest('wardrobe.ClientWardrobeSettingsPacket', {});\n }\n\n // Discovery\n listNotices() {\n return this.sendRequest('notices.ClientNoticeRequestPacket', {});\n }\n listServerDiscovery() {\n return this.sendRequest('serverdiscovery.ClientServerDiscoveryRequestPacket', {});\n }\n listKnownServers() {\n return this.sendRequest('knownservers.ClientKnownServersRequestPacket', {});\n }\n\n // Multiplayer\n relayIcePacket(targetUuid: string, payload: Uint8Array) {\n return this.sendRequest('multiplayer.ClientMultiplayerIceRelayPacket', {\n a: targetUuid,\n b: Array.from(payload),\n });\n }\n pingServer(host: string, port: number, protocolVersion?: number) {\n return this.sendRequest('pingproxy.ClientPingProxyRequestPacket', {\n a: host,\n b: port,\n c: protocolVersion ?? 0,\n });\n }\n\n // UPnP server hosting\n createSession(\n ip: string,\n port: number,\n privacy: 'PUBLIC' | 'FRIENDS' | 'INVITE_ONLY',\n worldName?: string,\n protocolVersion?: number,\n ) {\n return this.sendRequest('upnp.ClientUPnPSessionCreatePacket', {\n a: ip,\n b: port,\n c: privacy,\n d: protocolVersion,\n e: worldName,\n });\n }\n closeSession() {\n return this.sendRequest('upnp.ClientUPnPSessionClosePacket', {});\n }\n updateSession(patch: {\n ip?: string;\n port?: number;\n privacy?: 'PUBLIC' | 'FRIENDS' | 'INVITE_ONLY';\n }) {\n return this.sendRequest('upnp.ClientUPnPSessionUpdatePacket', {\n a: patch.ip,\n b: patch.port,\n c: patch.privacy,\n });\n }\n inviteToSession(inviteeUuids: string[]) {\n return this.sendRequest('upnp.ClientUPnPSessionInvitesAddPacket', { a: inviteeUuids });\n }\n revokeSessionInvites(inviteeUuids: string[]) {\n return this.sendRequest('upnp.ClientUPnPSessionInvitesRemovePacket', { a: inviteeUuids });\n }\n pushServerStatus(rawStatus: string) {\n return this.sendRequest('upnp.ClientUPnPSessionPingProxyUpdatePacket', { a: rawStatus });\n }\n\n // Social invite\n inviteFriendToServer(targetUuid: string, address: string) {\n return this.sendRequest('social.ClientSocialInviteRequestPacket', {\n a: targetUuid,\n b: address,\n });\n }\n\n // ----- Event emitter -----\n\n on<K extends keyof AnvilWsEvents>(event: K, listener: Listener<AnvilWsEvents[K]>): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n this.listeners.get(event)!.add(listener);\n return () => this.off(event, listener);\n }\n off<K extends keyof AnvilWsEvents>(event: K, listener: Listener<AnvilWsEvents[K]>): void {\n this.listeners.get(event)?.delete(listener);\n }\n private emit<K extends keyof AnvilWsEvents>(event: K, data: AnvilWsEvents[K]): void {\n for (const l of this.listeners.get(event) ?? []) {\n try {\n (l as Listener<AnvilWsEvents[K]>)(data);\n } catch (e) {\n /* swallow listener errors */\n }\n }\n }\n\n isReady(): boolean {\n return this.state === 'ready';\n }\n isConnected(): boolean {\n return this.state === 'connected' || this.state === 'ready';\n }\n}\n\n// ----- React hook helper -----\n\nimport { useEffect, useState } from 'react';\n\n/**\n * Subscribe to a WS event in a React component. The subscription\n * is cleaned up automatically on unmount.\n */\nexport function useWsEvent<K extends keyof AnvilWsEvents>(\n client: AnvilWsClient,\n event: K,\n handler: Listener<AnvilWsEvents[K]>,\n): void {\n useEffect(() => {\n const off = client.on(event, handler);\n return off;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, event]);\n}\n\n/**\n * Track connection state for a WS client. Returns the current\n * state ('disconnected' | 'connecting' | 'connected' | 'ready').\n */\nexport function useWsState(client: AnvilWsClient): AnvilWsClient['state'] | 'disconnected' {\n const [state, setState] = useState<AnvilWsClient['state']>(\n client.isConnected() ? (client.isReady() ? 'ready' : 'connected') : 'disconnected',\n );\n useEffect(() => {\n const update = () =>\n setState(client.isConnected() ? (client.isReady() ? 'ready' : 'connected') : 'disconnected');\n const off1 = client.on('open', update);\n const off2 = client.on('bootstrap', update);\n const off3 = client.on('close', update);\n return () => {\n off1();\n off2();\n off3();\n };\n }, [client]);\n return state;\n}\n"]}
@@ -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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anvil-js/client",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Anvil API client — tRPC router types, Zod schemas, React Query hooks and the Essential WS client.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,28 +11,59 @@
11
11
  "homepage": "https://anvil.my",
12
12
  "type": "module",
13
13
  "sideEffects": false,
14
- "main": "./dist/index.js",
14
+ "main": "./dist/index.cjs",
15
15
  "exports": {
16
16
  ".": {
17
- "types": "./dist/index.d.ts",
18
- "import": "./dist/index.js"
17
+ "import": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "require": {
22
+ "types": "./dist/index.d.cts",
23
+ "default": "./dist/index.cjs"
24
+ }
19
25
  },
20
26
  "./react": {
21
- "types": "./dist/react/index.d.ts",
22
- "import": "./dist/react/index.js"
27
+ "import": {
28
+ "types": "./dist/react/index.d.ts",
29
+ "default": "./dist/react/index.js"
30
+ },
31
+ "require": {
32
+ "types": "./dist/react/index.d.cts",
33
+ "default": "./dist/react/index.cjs"
34
+ }
23
35
  },
24
36
  "./schemas": {
25
- "types": "./dist/schemas/index.d.ts",
26
- "import": "./dist/schemas/index.js"
37
+ "import": {
38
+ "types": "./dist/schemas/index.d.ts",
39
+ "default": "./dist/schemas/index.js"
40
+ },
41
+ "require": {
42
+ "types": "./dist/schemas/index.d.cts",
43
+ "default": "./dist/schemas/index.cjs"
44
+ }
27
45
  },
28
46
  "./server": {
29
- "types": "./dist/server.d.ts",
30
- "import": "./dist/server.js"
47
+ "import": {
48
+ "types": "./dist/server.d.ts",
49
+ "default": "./dist/server.js"
50
+ },
51
+ "require": {
52
+ "types": "./dist/server.d.cts",
53
+ "default": "./dist/server.cjs"
54
+ }
31
55
  },
32
56
  "./ws": {
33
- "types": "./dist/ws/index.d.ts",
34
- "import": "./dist/ws/index.js"
35
- }
57
+ "import": {
58
+ "types": "./dist/ws/index.d.ts",
59
+ "default": "./dist/ws/index.js"
60
+ },
61
+ "require": {
62
+ "types": "./dist/ws/index.d.cts",
63
+ "default": "./dist/ws/index.cjs"
64
+ }
65
+ },
66
+ "./package.json": "./package.json"
36
67
  },
37
68
  "files": [
38
69
  "dist"
@@ -41,23 +72,31 @@
41
72
  "access": "public"
42
73
  },
43
74
  "dependencies": {
44
- "@tanstack/react-query": "^5.59.0",
45
75
  "@trpc/client": "^11.0.0-rc.660",
46
- "@trpc/react-query": "^11.0.0-rc.660",
47
76
  "@trpc/server": "^11.0.0-rc.660",
48
77
  "superjson": "^2.2.0",
49
78
  "uuid": "^11.0.0",
50
79
  "zod": "^3.23.0"
51
80
  },
52
81
  "devDependencies": {
82
+ "@tanstack/react-query": "^5.59.0",
83
+ "@trpc/react-query": "^11.0.0-rc.660",
53
84
  "@types/react": "^18.3.31",
54
85
  "tsup": "^8.3.0",
55
86
  "typescript": "^5.4.0"
56
87
  },
57
88
  "peerDependencies": {
89
+ "@tanstack/react-query": "^5.59.0",
90
+ "@trpc/react-query": "^11.0.0-rc.660",
58
91
  "react": "^18.0.0"
59
92
  },
60
93
  "peerDependenciesMeta": {
94
+ "@tanstack/react-query": {
95
+ "optional": true
96
+ },
97
+ "@trpc/react-query": {
98
+ "optional": true
99
+ },
61
100
  "react": {
62
101
  "optional": true
63
102
  }
@@ -1,41 +0,0 @@
1
- import { createTRPCReact } from '@trpc/react-query';
2
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3
- import { useState } from 'react';
4
- import { httpLink } from '@trpc/client';
5
- import { jsx } from 'react/jsx-runtime';
6
-
7
- // src/react/provider.tsx
8
- var trpc = createTRPCReact();
9
- function AnvilClientProvider({ config, children, devFetch }) {
10
- const [queryClient] = useState(
11
- () => new QueryClient({
12
- defaultOptions: {
13
- queries: {
14
- staleTime: 5 * 60 * 1e3,
15
- retry: 1,
16
- refetchOnWindowFocus: false
17
- }
18
- }
19
- })
20
- );
21
- const [trpcClient] = useState(
22
- () => trpc.createClient({
23
- links: [
24
- httpLink({
25
- url: config.baseUrl,
26
- headers: async () => {
27
- const token = await config.getToken();
28
- return token ? { authorization: `Bearer ${token}` } : {};
29
- },
30
- fetch: devFetch
31
- })
32
- ]
33
- })
34
- );
35
- return /* @__PURE__ */ jsx(trpc.Provider, { client: trpcClient, queryClient, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children }) });
36
- }
37
- var useAnvilClient = trpc.useContext;
38
-
39
- export { AnvilClientProvider, trpc, useAnvilClient };
40
- //# sourceMappingURL=chunk-DV6XOONA.js.map
41
- //# sourceMappingURL=chunk-DV6XOONA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/react/provider.tsx"],"names":[],"mappings":";;;;;;;AASO,IAAM,OAAO,eAAA;AAyEb,SAAS,mBAAA,CAAoB,EAAE,MAAA,EAAQ,QAAA,EAAU,UAAS,EAA6B;AAC5F,EAAA,MAAM,CAAC,WAAW,CAAA,GAAI,QAAA;AAAA,IACpB,MACE,IAAI,WAAA,CAAY;AAAA,MACd,cAAA,EAAgB;AAAA,QACd,OAAA,EAAS;AAAA,UACP,SAAA,EAAW,IAAI,EAAA,GAAK,GAAA;AAAA,UACpB,KAAA,EAAO,CAAA;AAAA,UACP,oBAAA,EAAsB;AAAA;AACxB;AACF,KACD;AAAA,GACL;AAEA,EAAA,MAAM,CAAC,UAAU,CAAA,GAAI,QAAA;AAAA,IAAS,MAC5B,KAAK,YAAA,CAAa;AAAA,MAChB,KAAA,EAAO;AAAA,QACL,QAAA,CAAS;AAAA,UACP,KAAK,MAAA,CAAO,OAAA;AAAA,UACZ,SAAS,YAAY;AACnB,YAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,QAAA,EAAS;AACpC,YAAA,OAAO,QAAQ,EAAE,aAAA,EAAe,UAAU,KAAK,CAAA,CAAA,KAAO,EAAC;AAAA,UACzD,CAAA;AAAA,UACA,KAAA,EAAO;AAAA,SACR;AAAA;AACH,KACD;AAAA,GACH;AAEA,EAAA,uBACE,GAAA,CAAC,IAAA,CAAK,QAAA,EAAL,EAAc,MAAA,EAAQ,UAAA,EAAY,WAAA,EACjC,QAAA,kBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,MAAA,EAAQ,WAAA,EAAc,QAAA,EAAS,CAAA,EACtD,CAAA;AAEJ;AAEO,IAAM,iBAAiB,IAAA,CAAK","file":"chunk-DV6XOONA.js","sourcesContent":["'use client';\n\nimport { createTRPCReact } from '@trpc/react-query';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useState, type ReactNode } from 'react';\nimport { httpLink } from '@trpc/client';\nimport type { AppRouter } from '../router';\nimport type { AnvilClientConfig } from '../client/factory';\n\nexport const trpc = createTRPCReact<AppRouter>();\n\nexport interface AnvilClientProviderProps {\n config: AnvilClientConfig;\n children: ReactNode;\n}\n\n/**\n * The Anvil tRPC client.\n *\n * History note: earlier versions of this provider used\n * `splitLink({ true: wsLink(...), false: httpBatchLink(...) })` so\n * subscription procedures would multiplex over a single WebSocket.\n * That setup opened a WebSocket on every mount, retried\n * indefinitely against `ws://localhost:3001/v1` (no real WS in dev),\n * spammed the console with \"ws connection error\", and held onto\n * EventSource handles that the GC couldn't free -- a noticeable\n * memory leak on the launcher tab.\n *\n * The router now has zero `subscription` procedures\n * (chat.subscribeChannel / social.presence.get are queries with\n * client-side polling, per Phase 5b / 6c). When real subscriptions\n * land, they should use a *dedicated* WS gateway with explicit\n * connect-on-subscribe semantics (tRPC v11 `createWSClient({ lazy: true })`)\n * so a tab with no active subscription never opens a socket.\n *\n * This scaffold uses `httpLink` (one request per call) instead of\n * `httpBatchLink`. Reason: the MSW dev layer returns a single\n * response object per registered handler. tRPC v11's batched GET\n * format (`?batch=1&input=...`) expects an array response\n * (`[{ result: { data } }, ...]`) and the dev path doesn't emit\n * that shape. Single-call links avoid the entire mismatch and keep\n * the dev path simple. When `apps/api` is wired, swapping back\n * to `httpBatchLink({ maxItems: 10 })` is a one-line change.\n */\nexport interface AnvilClientProviderProps {\n config: AnvilClientConfig;\n children: ReactNode;\n /**\n * Optional custom fetch for the in-process dev mock. When\n * provided, the tRPC client uses this fetch instead of the\n * real network. Production callers leave this undefined; the\n * `apps/web` dev bridge passes its own implementation.\n */\n devFetch?: typeof fetch;\n}\n\n/**\n * The Anvil tRPC client.\n *\n * History note: earlier versions of this provider used\n * `splitLink({ true: wsLink(...), false: httpBatchLink(...) })` so\n * subscription procedures would multiplex over a single WebSocket.\n * That setup opened a WebSocket on every mount, retried\n * indefinitely against `ws://localhost:3001/v1` (no real WS in dev),\n * spammed the console with \"ws connection error\", and held onto\n * EventSource handles that the GC couldn't free -- a noticeable\n * memory leak on the launcher tab.\n *\n * The router now has zero `subscription` procedures\n * (chat.subscribeChannel / social.presence.get are queries with\n * client-side polling, per Phase 5b / 6c). When real subscriptions\n * land, they should use a *dedicated* WS gateway with explicit\n * connect-on-subscribe semantics (tRPC v11 `createWSClient({ lazy: true })`)\n * so a tab with no active subscription never opens a socket.\n *\n * This scaffold uses `httpLink` with the default JSON transformer\n * (no superjson). For the dev renderer, a `devFetch` override\n * routes every request through the in-process mock registry in\n * `apps/web/src/lib/anvil-api/dev-fetch.ts`, bypassing the MSW\n * service worker entirely (which had wire-format issues with\n * tRPC v11's GET-batched queries).\n */\nexport function AnvilClientProvider({ config, children, devFetch }: AnvilClientProviderProps) {\n const [queryClient] = useState(\n () =>\n new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n }),\n );\n\n const [trpcClient] = useState(() =>\n trpc.createClient({\n links: [\n httpLink({\n url: config.baseUrl,\n headers: async () => {\n const token = await config.getToken();\n return token ? { authorization: `Bearer ${token}` } : {};\n },\n fetch: devFetch,\n }),\n ],\n }),\n );\n\n return (\n <trpc.Provider client={trpcClient} queryClient={queryClient}>\n <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>\n </trpc.Provider>\n );\n}\n\nexport const useAnvilClient = trpc.useContext;\n"]}