@shaunlwm/pickle.ts 0.3.0 → 0.4.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.
package/dist/index.d.ts CHANGED
@@ -94,9 +94,22 @@ declare class CplegacyAdapter extends BaseAdapter {
94
94
  private postLogin;
95
95
  }
96
96
 
97
+ declare class NewcpAdapter extends BaseAdapter {
98
+ readonly id = "NewCP";
99
+ private encryptor;
100
+ private worlds;
101
+ login(options: LoginOptions | TokenLoginOptions): Promise<LoginResult>;
102
+ connect(serverName: string, loginResult: LoginResult, options?: ConnectOptions): Promise<Socket>;
103
+ send(action: string, args: Record<string, unknown>): void;
104
+ disconnect(): void;
105
+ private createSocket;
106
+ private loadWorlds;
107
+ }
108
+
97
109
  declare const ADAPTERS: {
98
110
  readonly CPJourney: typeof CpjourneyAdapter;
99
111
  readonly CPLegacy: typeof CplegacyAdapter;
112
+ readonly NewCP: typeof NewcpAdapter;
100
113
  };
101
114
  type AdapterName = keyof typeof ADAPTERS;
102
115
 
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{EventEmitter as A}from"events";import{io as f}from"socket.io-client";import w from"socket.io-msgpack-parser";var m=class{socket=null;sendMessage(e){this.send("send_message",{message:e})}sendEmote(e){this.send("send_emote",{emote:e})}sendSafe(e){this.send("send_safe",{safe:e})}walk(e,s){this.send("send_position",{x:e,y:s})}sendFrame(e,s){this.send("send_frame",{frame:e,set:s})}snowball(e,s){this.send("snowball",{x:e,y:s})}joinRoom(e,s,o){this.send("join_room",{room:e,x:s??0,y:o??0})}addItem(e){this.send("add_item",{item:e})}equipColor(e){this.send("update_color",{item:e})}equipHead(e){this.send("update_head",{item:e})}equipFace(e){this.send("update_face",{item:e})}equipNeck(e){this.send("update_neck",{item:e})}equipBody(e){this.send("update_body",{item:e})}equipHand(e){this.send("update_hand",{item:e})}equipFeet(e){this.send("update_feet",{item:e})}equipFlag(e){this.send("update_flag",{item:e})}equipPhoto(e){this.send("update_photo",{item:e})}buddyRequest(e){this.send("buddy_request",{id:e})}buddyAccept(e){this.send("buddy_accept",{id:e})}buddyReject(e){this.send("buddy_reject",{id:e})}buddyRequestSeen(e){this.send("buddy_request_seen",{id:e})}getBuddy(e,s){this.send("get_buddy",{id:e,type:s})}removeBuddy(e){this.send("remove_buddy",{id:e})}addIgnore(e){this.send("ignore_add",{id:e})}removeIgnore(e){this.send("ignore_remove",{id:e})}getPlayer(e){this.send("get_player",{id:e})}getAllSlots(){this.send("get_all_slots",{})}getMascots(){this.send("get_mascots",{})}sendPostcard(e,s){this.send("send_postcard",{userId:e,cardId:s})}getStamps(e){this.send("get_stamps",{userId:e})}getPostcards(){this.send("get_postcards",{})}getIglooOpen(e){this.send("get_igloo_open",{igloo:e})}joinIgloo(e,s,o){this.send("join_igloo",{igloo:e,x:s??0,y:o??0})}gameOver(e){this.send("game_over",{coins:e})}collectStamp(e){this.send("collect_stamp",{stamp:e})}};var _="wss://play.cpjourney.net",S="skip",l=class extends m{id="CPJourney";async login(e){let s=this.createSocket("/world/login/");return await new Promise((t,n)=>{let r=setTimeout(()=>{s.disconnect(),n(new Error("Login timed out"))},1e4);s.on("connect",()=>{let i=e.secret??S,a="token"in e?{username:e.username,token:e.token,secret:i}:{username:e.username,password:e.password,secret:i};s.emit("message",{action:"login",args:a})}),s.on("message",i=>{if(i.action!=="login")return;clearTimeout(r),s.disconnect();let a=i.args;if(!a.success){n(new Error("Login failed"));return}let u=Object.entries(a.populations).map(([c,p])=>({name:c,population:p}));t({servers:u,key:a.key,username:a.username,moderator:a.moderator,buddyWorlds:a.buddyWorlds??[]})}),s.on("connect_error",i=>{clearTimeout(r),s.disconnect(),n(new Error(`Login connection failed: ${i.message}`))})})}async connect(e,s,o){let t=this.createSocket(`/world/${e.toLowerCase()}/`);return this.socket=t,await new Promise((n,r)=>{let i=!1;t.on("connect",()=>{t.emit("message",{action:"game_auth",args:{username:s.username,key:s.key,createToken:!1,joinInvis:!1,takeoverMascot:!1,token:""}})}),t.on("message",a=>{switch(a.action){case"wait_queue_update":{o?.onQueueUpdate?.(a.args);break}case"game_auth":{if(i)break;if(i=!0,!a.args.success){t.disconnect(),r(new Error("Game auth failed"));return}t.emit("message",{action:"join_server",args:{}}),n();break}}}),t.on("connect_error",a=>{t.disconnect(),r(new Error(`Game connection failed: ${a.message}`))})}),t}send(e,s){if(!this.socket)throw new Error("Not connected");this.socket.emit("message",{action:e,args:s})}disconnect(){this.socket?.disconnect(),this.socket=null}createSocket(e){return f(_,{path:e,parser:w,transports:["polling","websocket"],reconnection:!1})}};import{io as R}from"socket.io-client";import L from"socket.io-msgpack-parser";var P="https://api.cplegacy.com/login",O="https://api.cplegacy.com/token_login";function q(d){let e=d.on.bind(d);return d.on=function(s,o){return s==="message"?e(s,(t,n)=>{o({action:t,args:n??{}})}):e(s,o)},d}var h=class extends m{id="CPLegacy";version="";async login(e){let s="token"in e?O:P,o="token"in e?{username:e.username,token:e.token}:{username:e.username,password:e.password,version:this.version},t=await this.postLogin(s,o);if(!t.success&&t.wantedVersion&&(this.version=t.wantedVersion,o.version=this.version,t=await this.postLogin(s,o)),!t.success)throw new Error(`Login failed: ${t.message??"unknown error"}`);return{servers:Object.entries(t.populations??{}).map(([r,i])=>({name:r,population:i})),key:t.key,username:t.username,moderator:!1,buddyWorlds:[]}}async connect(e,s,o){let t=`wss://${e.toLowerCase()}.server.cplegacy.com`,n=R(t,{path:"/socket.io/",parser:L,transports:["websocket"],reconnection:!1});return this.socket=n,await new Promise((r,i)=>{let a=setTimeout(()=>{n.disconnect(),i(new Error("Game connection timed out"))},15e3);n.on("connect",()=>{n.emit("message","game_auth",{username:s.username,key:s.key,createToken:!1,token:""})}),n.on("message",(u,c)=>{switch(u){case"wait_queue_update":{o?.onQueueUpdate?.(c);break}case"game_auth":{if(!c.success){clearTimeout(a),n.disconnect(),i(new Error("Game auth failed"));return}n.emit("message","load_player",{}),n.emit("message","join_server",{}),clearTimeout(a),r();break}}}),n.on("connect_error",u=>{clearTimeout(a),n.disconnect(),i(new Error(`Game connection failed: ${u.message}`))})}),q(n)}send(e,s){if(!this.socket)throw new Error("Not connected");this.socket.emit("message",e,s)}disconnect(){this.socket?.disconnect(),this.socket=null}async postLogin(e,s){return(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(s)})).json()}};var M={CPJourney:l,CPLegacy:h};function v(d){return new M[d]}function y(d){return typeof d=="object"&&d!==null&&"action"in d&&"args"in d}var b=class extends A{player=null;room=null;users=new Map;connected=!1;adapter;loginResult=null;log=null;constructor(e,s){super(),this.adapter=v(e),s?.debug&&(this.log=typeof s.debug=="function"?s.debug:console.log.bind(console))}async login(e){return this.log?.("[login] logging in as",e.username),this.loginResult=await this.adapter.login(e),this.log?.("[login] success \u2014",this.loginResult.servers.length,"servers"),this.loginResult.servers}async connect(e,s){if(!this.loginResult)throw new Error("Must call login() first");this.log?.("[connect] joining",e);let o={...s,onQueueUpdate:n=>{this.log?.("[queue]",`#${n.position}/${n.queueLength}`),this.emit("wait_queue_update",n),s?.onQueueUpdate?.(n)}},t=await this.adapter.connect(e,this.loginResult,o);t.on("message",n=>{y(n)&&this.handleMessage(n)}),t.on("disconnect",()=>{this.log?.("[disconnect] connection lost"),this.cleanup(),this.emit("disconnect")}),await new Promise((n,r)=>{let i=setTimeout(()=>{r(new Error("Waiting for load_player timed out"))},1e4),a=!1,u=!1,c=()=>{a&&u&&(clearTimeout(i),this.connected=!0,n())},p=g=>{if(y(g))switch(g.action){case"load_player":a=!0,c();break;case"join_room":u=!0,c();break;case"kick":clearTimeout(i),t.off("message",p),r(new Error(`Kicked: ${g.args.reason??"unknown"}`));break;case"close_with_error":clearTimeout(i),t.off("message",p),r(new Error(`Kicked: ${g.args.error??"unknown"}`));break;case"error":clearTimeout(i),t.off("message",p),r(new Error(`Server error: ${g.args.error??"unknown"}`));break}},k=()=>{(!a||!u)&&(clearTimeout(i),r(new Error("Disconnected before fully loaded")))};t.on("message",p),t.once("disconnect",k)})}on(e,s){return super.on(e,s)}off(e,s){return super.off(e,s)}once(e,s){return super.once(e,s)}emit(e,...s){return super.emit(e,...s)}sendMessage(e){this.adapter.sendMessage(e)}sendEmote(e){this.adapter.sendEmote(e)}sendSafe(e){this.adapter.sendSafe(e)}walk(e,s){this.adapter.walk(e,s)}sendFrame(e,s){this.adapter.sendFrame(e,s)}snowball(e,s){this.adapter.snowball(e,s)}joinRoom(e,s,o){this.adapter.joinRoom(e,s,o)}addItem(e){this.adapter.addItem(e)}equipColor(e){this.adapter.equipColor(e)}equipHead(e){this.adapter.equipHead(e)}equipFace(e){this.adapter.equipFace(e)}equipNeck(e){this.adapter.equipNeck(e)}equipBody(e){this.adapter.equipBody(e)}equipHand(e){this.adapter.equipHand(e)}equipFeet(e){this.adapter.equipFeet(e)}equipFlag(e){this.adapter.equipFlag(e)}equipPhoto(e){this.adapter.equipPhoto(e)}buddyRequest(e){this.adapter.buddyRequest(e)}buddyAccept(e){this.adapter.buddyAccept(e)}buddyReject(e){this.adapter.buddyReject(e)}buddyRequestSeen(e){this.adapter.buddyRequestSeen(e)}getBuddy(e,s){this.adapter.getBuddy(e,s)}removeBuddy(e){this.adapter.removeBuddy(e)}addIgnore(e){this.adapter.addIgnore(e)}removeIgnore(e){this.adapter.removeIgnore(e)}getPlayer(e){this.adapter.getPlayer(e)}getAllSlots(){this.adapter.getAllSlots()}getMascots(){this.adapter.getMascots()}sendPostcard(e,s){this.adapter.sendPostcard(e,s)}getStamps(e){this.adapter.getStamps(e)}getPostcards(){this.adapter.getPostcards()}getIglooOpen(e){this.adapter.getIglooOpen(e)}joinIgloo(e,s,o){this.adapter.joinIgloo(e,s,o)}gameOver(e){this.adapter.gameOver(e)}collectStamp(e){this.adapter.collectStamp(e)}sleep(e){return new Promise(s=>setTimeout(s,e))}disconnect(){this.log?.("[disconnect] closing connection"),this.adapter.disconnect(),this.cleanup()}cleanup(){this.connected=!1,this.player=null,this.room=null,this.users.clear()}handleMessage(e){let{action:s,args:o}=e;switch(s){case"load_player":{let n=o.user;n.coins=o.coins??0,n.inventory=o.inventory??[],n.furniture=o.furniture??[],n.flooring=o.flooring??[],n.rank=o.rank??0,this.player=n,this.log?.("[load_player]",n.username,`id=${n.id}`,`coins=${n.coins}`,`inventory=${n.inventory.length}`);break}case"join_room":{let n=o.room,r=o.users;this.room=n,this.users.clear();for(let i of r)this.users.set(i.id,i);this.log?.("[join_room]",`room=${n}`,`users=${r.length}`);break}case"add_player":{let n=o.user;this.users.set(n.id,n),this.log?.("[add_player]",n.username,`id=${n.id}`);break}case"remove_player":{let n=o.user;this.users.delete(n),this.log?.("[remove_player]",`id=${n}`);break}case"send_position":{let n=o.id,r=this.users.get(n);r&&(r.x=o.x,r.y=o.y);break}case"send_frame":{let n=o.id,r=this.users.get(n);r&&(r.frame=o.frame);break}case"update_player":{let n=o.id,r=o.slot,i=o.item,a=this.users.get(n);a&&r in a&&(a[r]=i);break}case"kick":{let n=o.reason??"unknown";this.log?.("[kick]",n),this.cleanup();break}case"close_with_error":{let n=o.error??"unknown";this.log?.("[kick]",n),this.cleanup();break}default:{this.log?.(`[${s}]`,JSON.stringify(o));break}}let t=s==="error"?"server_error":s;this.emit(t,o)}};export{m as BaseAdapter,b as Client};
1
+ import{EventEmitter as N}from"events";import{io as R}from"socket.io-client";import L from"socket.io-msgpack-parser";var m=class{socket=null;sendMessage(e){this.send("send_message",{message:e})}sendEmote(e){this.send("send_emote",{emote:e})}sendSafe(e){this.send("send_safe",{safe:e})}walk(e,n){this.send("send_position",{x:e,y:n})}sendFrame(e,n){this.send("send_frame",{frame:e,set:n})}snowball(e,n){this.send("snowball",{x:e,y:n})}joinRoom(e,n,s){this.send("join_room",{room:e,x:n??0,y:s??0})}addItem(e){this.send("add_item",{item:e})}equipColor(e){this.send("update_color",{item:e})}equipHead(e){this.send("update_head",{item:e})}equipFace(e){this.send("update_face",{item:e})}equipNeck(e){this.send("update_neck",{item:e})}equipBody(e){this.send("update_body",{item:e})}equipHand(e){this.send("update_hand",{item:e})}equipFeet(e){this.send("update_feet",{item:e})}equipFlag(e){this.send("update_flag",{item:e})}equipPhoto(e){this.send("update_photo",{item:e})}buddyRequest(e){this.send("buddy_request",{id:e})}buddyAccept(e){this.send("buddy_accept",{id:e})}buddyReject(e){this.send("buddy_reject",{id:e})}buddyRequestSeen(e){this.send("buddy_request_seen",{id:e})}getBuddy(e,n){this.send("get_buddy",{id:e,type:n})}removeBuddy(e){this.send("remove_buddy",{id:e})}addIgnore(e){this.send("ignore_add",{id:e})}removeIgnore(e){this.send("ignore_remove",{id:e})}getPlayer(e){this.send("get_player",{id:e})}getAllSlots(){this.send("get_all_slots",{})}getMascots(){this.send("get_mascots",{})}sendPostcard(e,n){this.send("send_postcard",{userId:e,cardId:n})}getStamps(e){this.send("get_stamps",{userId:e})}getPostcards(){this.send("get_postcards",{})}getIglooOpen(e){this.send("get_igloo_open",{igloo:e})}joinIgloo(e,n,s){this.send("join_igloo",{igloo:e,x:n??0,y:s??0})}gameOver(e){this.send("game_over",{coins:e})}collectStamp(e){this.send("collect_stamp",{stamp:e})}};var O="wss://play.cpjourney.net",P="skip",h=class extends m{id="CPJourney";async login(e){let n=this.createSocket("/world/login/");return await new Promise((o,t)=>{let i=setTimeout(()=>{n.disconnect(),t(new Error("Login timed out"))},1e4);n.on("connect",()=>{let a=e.secret??P,r="token"in e?{username:e.username,token:e.token,secret:a}:{username:e.username,password:e.password,secret:a};n.emit("message",{action:"login",args:r})}),n.on("message",a=>{if(a.action!=="login")return;clearTimeout(i),n.disconnect();let r=a.args;if(!r.success){t(new Error("Login failed"));return}let c=Object.entries(r.populations).map(([u,p])=>({name:u,population:p}));o({servers:c,key:r.key,username:r.username,moderator:r.moderator,buddyWorlds:r.buddyWorlds??[]})}),n.on("connect_error",a=>{clearTimeout(i),n.disconnect(),t(new Error(`Login connection failed: ${a.message}`))})})}async connect(e,n,s){let o=this.createSocket(`/world/${e.toLowerCase()}/`);return this.socket=o,await new Promise((t,i)=>{let a=!1;o.on("connect",()=>{o.emit("message",{action:"game_auth",args:{username:n.username,key:n.key,createToken:!1,joinInvis:!1,takeoverMascot:!1,token:""}})}),o.on("message",r=>{switch(r.action){case"wait_queue_update":{s?.onQueueUpdate?.(r.args);break}case"game_auth":{if(a)break;if(a=!0,!r.args.success){o.disconnect(),i(new Error("Game auth failed"));return}o.emit("message",{action:"join_server",args:{}}),t();break}}}),o.on("connect_error",r=>{o.disconnect(),i(new Error(`Game connection failed: ${r.message}`))})}),o}send(e,n){if(!this.socket)throw new Error("Not connected");this.socket.emit("message",{action:e,args:n})}disconnect(){this.socket?.disconnect(),this.socket=null}createSocket(e){return R(O,{path:e,parser:L,transports:["polling","websocket"],reconnection:!1})}};import{io as E}from"socket.io-client";import T from"socket.io-msgpack-parser";var q="https://api.cplegacy.com/login",x="https://api.cplegacy.com/token_login";function A(d){let e=d.on.bind(d);return d.on=function(n,s){return n==="message"?e(n,(o,t)=>{s({action:o,args:t??{}})}):e(n,s)},d}var b=class extends m{id="CPLegacy";version="";async login(e){let n="token"in e?x:q,s="token"in e?{username:e.username,token:e.token}:{username:e.username,password:e.password,version:this.version},o=await this.postLogin(n,s);if(!o.success&&o.wantedVersion&&(this.version=o.wantedVersion,s.version=this.version,o=await this.postLogin(n,s)),!o.success)throw new Error(`Login failed: ${o.message??"unknown error"}`);return{servers:Object.entries(o.populations??{}).map(([i,a])=>({name:i,population:a})),key:o.key,username:o.username,moderator:!1,buddyWorlds:[]}}async connect(e,n,s){let o=`wss://${e.toLowerCase()}.server.cplegacy.com`,t=E(o,{path:"/socket.io/",parser:T,transports:["websocket"],reconnection:!1});return this.socket=t,await new Promise((i,a)=>{let r=setTimeout(()=>{t.disconnect(),a(new Error("Game connection timed out"))},15e3);t.on("connect",()=>{t.emit("message","game_auth",{username:n.username,key:n.key,createToken:!1,token:""})}),t.on("message",(c,u)=>{switch(c){case"wait_queue_update":{s?.onQueueUpdate?.(u);break}case"game_auth":{if(!u.success){clearTimeout(r),t.disconnect(),a(new Error("Game auth failed"));return}t.emit("message","load_player",{}),t.emit("message","join_server",{}),clearTimeout(r),i();break}}}),t.on("connect_error",c=>{clearTimeout(r),t.disconnect(),a(new Error(`Game connection failed: ${c.message}`))})}),A(t)}send(e,n){if(!this.socket)throw new Error("Not connected");this.socket.emit("message",e,n)}disconnect(){this.socket?.disconnect(),this.socket=null}async postLogin(e,n){return(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(n)})).json()}};import{createCipheriv as C,createDecipheriv as M,randomBytes as K}from"crypto";import{io as U}from"socket.io-client";import k from"tweetnacl";var B="https://media8.newcp.net/assets/media/crumbs/en/crumbs.json",y=class{aesKey=null;keypair=k.box.keyPair();get publicKey(){return Buffer.from(this.keypair.publicKey).toString("base64")}get encrypted(){return this.aesKey!==null}acquireKey(e,n){let s=Buffer.from(e,"base64"),o=Buffer.from(n,"base64"),t=s.subarray(0,k.box.nonceLength),i=s.subarray(k.box.nonceLength),a=k.box.open(new Uint8Array(i),new Uint8Array(t),new Uint8Array(o),this.keypair.secretKey);return a?new TextDecoder().decode(a):null}setKey(e){this.aesKey=Buffer.from(e,"utf-8")}encrypt(e){if(!this.aesKey)throw new Error("Encryption key not set");let n=K(16),s=C("aes-256-cbc",this.aesKey,n),o=Buffer.concat([s.update(e,"utf-8"),s.final()]);return Buffer.concat([n,o]).toString("base64")}decrypt(e){if(!this.aesKey)throw new Error("Encryption key not set");let n=Buffer.from(e,"base64"),s=n.subarray(0,16),o=n.subarray(16),t=M("aes-256-cbc",this.aesKey,s);return Buffer.concat([t.update(o),t.final()]).toString("utf-8")}encode(e){return this.encrypted?this.encrypt(JSON.stringify(e)):JSON.stringify(e)}decode(e){return this.encrypted&&typeof e=="string"?JSON.parse(this.decrypt(e)):typeof e=="string"?JSON.parse(e):e}};function w(d,e){return new Promise((n,s)=>{let o=setTimeout(()=>{s(new Error("Handshake timed out"))},1e4);d.once("handshake",(t,i)=>{clearTimeout(o);let a=e.acquireKey(t,i);if(!a){s(new Error("Failed to decrypt handshake key"));return}let r=JSON.parse(a);if(r.time&&typeof r.time=="number"&&Math.abs(Date.now()-r.time)>3e5){s(new Error("Server time desync"));return}e.setKey(r.key),n()}),d.emit("handshake",e.publicKey)})}function j(d,e){let n=d.on.bind(d);return d.on=function(s,o){return s==="message"?n(s,t=>{try{let i=e.decode(t);o({action:i.action,args:i.args??{}})}catch{}}):n(s,o)},d}var f=class extends m{id="NewCP";encryptor=new y;worlds=null;async login(e){this.worlds||await this.loadWorlds();let n=Object.values(this.worlds).find(t=>t.login);if(!n)throw new Error("Login world not found in crumbs");let s=this.createSocket(n.host,n.path);return this.encryptor=new y,await new Promise((t,i)=>{let a=setTimeout(()=>{s.disconnect(),i(new Error("Login timed out"))},15e3);s.on("connect",async()=>{try{await w(s,this.encryptor);let r="token"in e?{username:e.username,token:e.token}:{username:e.username,password:e.password},c=this.encryptor.encode({action:"login",args:r});s.emit("message",c)}catch(r){clearTimeout(a),s.disconnect(),i(r)}}),s.on("message",r=>{try{let c=this.encryptor.decode(r);if(c.action!=="login")return;clearTimeout(a),s.disconnect();let u=c.args;if(!u.success){i(new Error("Login failed"));return}let p=Object.entries(u.populations??{}).map(([l,g])=>({name:l,population:g}));t({servers:p,key:u.key,username:u.username,moderator:u.moderator??!1,buddyWorlds:u.buddyWorlds??[]})}catch(c){clearTimeout(a),s.disconnect(),i(c)}}),s.on("connect_error",r=>{clearTimeout(a),s.disconnect(),i(new Error(`Login connection failed: ${r.message}`))})})}async connect(e,n,s){this.worlds||await this.loadWorlds();let o=this.worlds[e];if(!o)throw new Error(`World config not found for: ${e}`);this.encryptor=new y;let t=this.createSocket(o.host,o.path);return this.socket=t,await new Promise((i,a)=>{let r=setTimeout(()=>{t.disconnect(),a(new Error("Game connection timed out"))},15e3);t.on("connect",async()=>{try{await w(t,this.encryptor);let c=this.encryptor.encode({action:"game_auth",args:{username:n.username,key:n.key,createToken:!1}});t.emit("message",c)}catch(c){clearTimeout(r),t.disconnect(),a(c)}}),t.on("message",c=>{try{let u=this.encryptor.decode(c);switch(u.action){case"wait_queue_update":{s?.onQueueUpdate?.(u.args);break}case"game_auth":{if(!u.args.success){clearTimeout(r),t.disconnect(),a(new Error("Game auth failed"));return}let l=this.encryptor.encode({action:"join_server",args:{}});t.emit("message",l),clearTimeout(r),i();break}}}catch{}}),t.on("connect_error",c=>{clearTimeout(r),t.disconnect(),a(new Error(`Game connection failed: ${c.message}`))})}),j(t,this.encryptor)}send(e,n){if(!this.socket)throw new Error("Not connected");let s=this.encryptor.encode({action:e,args:n});this.socket.emit("message",s)}disconnect(){this.socket?.disconnect(),this.socket=null}createSocket(e,n){return U(e,{path:n,transports:["polling","websocket"],reconnection:!1})}async loadWorlds(){let e=await fetch(B);if(!e.ok)throw new Error(`Failed to fetch crumbs: ${e.status}`);let n=await e.json();this.worlds=n.worlds}};var I={CPJourney:h,CPLegacy:b,NewCP:f};function _(d){return new I[d]}function S(d){return typeof d=="object"&&d!==null&&"action"in d&&"args"in d}var v=class extends N{player=null;room=null;users=new Map;connected=!1;adapter;loginResult=null;log=null;constructor(e,n){super(),this.adapter=_(e),n?.debug&&(this.log=typeof n.debug=="function"?n.debug:console.log.bind(console))}async login(e){return this.log?.("[login] logging in as",e.username),this.loginResult=await this.adapter.login(e),this.log?.("[login] success \u2014",this.loginResult.servers.length,"servers"),this.loginResult.servers}async connect(e,n){if(!this.loginResult)throw new Error("Must call login() first");this.log?.("[connect] joining",e);let s={...n,onQueueUpdate:t=>{this.log?.("[queue]",`#${t.position}/${t.queueLength}`),this.emit("wait_queue_update",t),n?.onQueueUpdate?.(t)}},o=await this.adapter.connect(e,this.loginResult,s);o.on("message",t=>{S(t)&&this.handleMessage(t)}),o.on("disconnect",()=>{this.log?.("[disconnect] connection lost"),this.cleanup(),this.emit("disconnect")}),await new Promise((t,i)=>{let a=setTimeout(()=>{i(new Error("Waiting for load_player timed out"))},1e4),r=!1,c=!1,u=()=>{r&&c&&(clearTimeout(a),this.connected=!0,t())},p=g=>{if(S(g))switch(g.action){case"load_player":r=!0,u();break;case"join_room":c=!0,u();break;case"kick":clearTimeout(a),o.off("message",p),i(new Error(`Kicked: ${g.args.reason??"unknown"}`));break;case"close_with_error":clearTimeout(a),o.off("message",p),i(new Error(`Kicked: ${g.args.error??"unknown"}`));break;case"error":clearTimeout(a),o.off("message",p),i(new Error(`Server error: ${g.args.error??"unknown"}`));break}},l=()=>{(!r||!c)&&(clearTimeout(a),i(new Error("Disconnected before fully loaded")))};o.on("message",p),o.once("disconnect",l)})}on(e,n){return super.on(e,n)}off(e,n){return super.off(e,n)}once(e,n){return super.once(e,n)}emit(e,...n){return super.emit(e,...n)}sendMessage(e){this.adapter.sendMessage(e)}sendEmote(e){this.adapter.sendEmote(e)}sendSafe(e){this.adapter.sendSafe(e)}walk(e,n){this.adapter.walk(e,n)}sendFrame(e,n){this.adapter.sendFrame(e,n)}snowball(e,n){this.adapter.snowball(e,n)}joinRoom(e,n,s){this.adapter.joinRoom(e,n,s)}addItem(e){this.adapter.addItem(e)}equipColor(e){this.adapter.equipColor(e)}equipHead(e){this.adapter.equipHead(e)}equipFace(e){this.adapter.equipFace(e)}equipNeck(e){this.adapter.equipNeck(e)}equipBody(e){this.adapter.equipBody(e)}equipHand(e){this.adapter.equipHand(e)}equipFeet(e){this.adapter.equipFeet(e)}equipFlag(e){this.adapter.equipFlag(e)}equipPhoto(e){this.adapter.equipPhoto(e)}buddyRequest(e){this.adapter.buddyRequest(e)}buddyAccept(e){this.adapter.buddyAccept(e)}buddyReject(e){this.adapter.buddyReject(e)}buddyRequestSeen(e){this.adapter.buddyRequestSeen(e)}getBuddy(e,n){this.adapter.getBuddy(e,n)}removeBuddy(e){this.adapter.removeBuddy(e)}addIgnore(e){this.adapter.addIgnore(e)}removeIgnore(e){this.adapter.removeIgnore(e)}getPlayer(e){this.adapter.getPlayer(e)}getAllSlots(){this.adapter.getAllSlots()}getMascots(){this.adapter.getMascots()}sendPostcard(e,n){this.adapter.sendPostcard(e,n)}getStamps(e){this.adapter.getStamps(e)}getPostcards(){this.adapter.getPostcards()}getIglooOpen(e){this.adapter.getIglooOpen(e)}joinIgloo(e,n,s){this.adapter.joinIgloo(e,n,s)}gameOver(e){this.adapter.gameOver(e)}collectStamp(e){this.adapter.collectStamp(e)}sleep(e){return new Promise(n=>setTimeout(n,e))}disconnect(){this.log?.("[disconnect] closing connection"),this.adapter.disconnect(),this.cleanup()}cleanup(){this.connected=!1,this.player=null,this.room=null,this.users.clear()}handleMessage(e){let{action:n,args:s}=e;switch(n){case"load_player":{let t=s.user;t.coins=s.coins??0,t.inventory=s.inventory??[],t.furniture=s.furniture??[],t.flooring=s.flooring??[],t.rank=s.rank??0,this.player=t,this.log?.("[load_player]",t.username,`id=${t.id}`,`coins=${t.coins}`,`inventory=${t.inventory.length}`);break}case"join_room":{let t=s.room,i=s.users;this.room=t,this.users.clear();for(let a of i)this.users.set(a.id,a);this.log?.("[join_room]",`room=${t}`,`users=${i.length}`);break}case"add_player":{let t=s.user;this.users.set(t.id,t),this.log?.("[add_player]",t.username,`id=${t.id}`);break}case"remove_player":{let t=s.user;this.users.delete(t),this.log?.("[remove_player]",`id=${t}`);break}case"send_position":{let t=s.id,i=this.users.get(t);i&&(i.x=s.x,i.y=s.y);break}case"send_frame":{let t=s.id,i=this.users.get(t);i&&(i.frame=s.frame);break}case"update_player":{let t=s.id,i=s.slot,a=s.item,r=this.users.get(t);r&&i in r&&(r[i]=a);break}case"kick":{let t=s.reason??"unknown";this.log?.("[kick]",t),this.cleanup();break}case"close_with_error":{let t=s.error??"unknown";this.log?.("[kick]",t),this.cleanup();break}default:{this.log?.(`[${n}]`,JSON.stringify(s));break}}let o=n==="error"?"server_error":n;this.emit(o,s)}};export{m as BaseAdapter,v as Client};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/adapters/cpjourney-adapter.ts","../src/adapters/base-adapter.ts","../src/adapters/cplegacy-adapter.ts","../src/adapters/index.ts"],"sourcesContent":["import { EventEmitter } from \"node:events\"\nimport { createAdapter, type AdapterName } from \"./adapters/index.js\"\nimport type { BaseAdapter, ConnectOptions } from \"./adapters/base-adapter.js\"\nimport type { LoginOptions, LoginResult, QueueUpdate, ServerInfo, TokenLoginOptions } from \"./types/adapter-types.js\"\nimport type { ServerMessages } from \"./types/message-types.js\"\nimport type { PlayerData, RoomUser } from \"./types/player-types.js\"\n\ntype ServerMessageHandler<K extends keyof ServerMessages> = (args: ServerMessages[K]) => void\n\nexport type LogFn = (message: string, ...args: unknown[]) => void\n\nexport type ClientOptions = {\n debug?: boolean | LogFn\n}\n\ntype MessagePayload = {\n action: string\n args: Record<string, unknown>\n}\n\nfunction isMessagePayload(msg: unknown): msg is MessagePayload {\n return typeof msg === \"object\" && msg !== null && \"action\" in msg && \"args\" in msg\n}\n\nexport class Client extends EventEmitter {\n player: PlayerData | null = null\n room: number | null = null\n users: Map<number, RoomUser> = new Map()\n connected = false\n\n private adapter: BaseAdapter\n private loginResult: LoginResult | null = null\n private log: LogFn | null = null\n\n constructor(server: AdapterName, options?: ClientOptions) {\n super()\n this.adapter = createAdapter(server)\n\n if (options?.debug) {\n this.log = typeof options.debug === \"function\"\n ? options.debug\n : console.log.bind(console)\n }\n }\n\n async login(options: LoginOptions | TokenLoginOptions): Promise<ServerInfo[]> {\n this.log?.(\"[login] logging in as\", options.username)\n this.loginResult = await this.adapter.login(options)\n this.log?.(\"[login] success —\", this.loginResult.servers.length, \"servers\")\n return this.loginResult.servers\n }\n\n async connect(serverName: string, options?: ConnectOptions): Promise<void> {\n if (!this.loginResult) throw new Error(\"Must call login() first\")\n\n this.log?.(\"[connect] joining\", serverName)\n\n const connectOptions: ConnectOptions = {\n ...options,\n onQueueUpdate: (update: QueueUpdate) => {\n this.log?.(\"[queue]\", `#${update.position}/${update.queueLength}`)\n this.emit(\"wait_queue_update\", update)\n options?.onQueueUpdate?.(update)\n },\n }\n\n const socket = await this.adapter.connect(serverName, this.loginResult, connectOptions)\n\n socket.on(\"message\", (msg: unknown) => {\n if (!isMessagePayload(msg)) return\n this.handleMessage(msg)\n })\n\n socket.on(\"disconnect\", () => {\n this.log?.(\"[disconnect] connection lost\")\n this.cleanup()\n this.emit(\"disconnect\")\n })\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(\"Waiting for load_player timed out\"))\n }, 10_000)\n\n let playerLoaded = false\n let roomJoined = false\n\n const checkReady = (): void => {\n if (playerLoaded && roomJoined) {\n clearTimeout(timeout)\n this.connected = true\n resolve()\n }\n }\n\n const onMessage = (msg: unknown): void => {\n if (!isMessagePayload(msg)) return\n switch (msg.action) {\n case \"load_player\":\n playerLoaded = true\n checkReady()\n break\n case \"join_room\":\n roomJoined = true\n checkReady()\n break\n case \"kick\":\n clearTimeout(timeout)\n socket.off(\"message\", onMessage)\n reject(new Error(`Kicked: ${(msg.args as { reason?: string }).reason ?? \"unknown\"}`))\n break\n case \"close_with_error\":\n clearTimeout(timeout)\n socket.off(\"message\", onMessage)\n reject(new Error(`Kicked: ${(msg.args as { error?: string }).error ?? \"unknown\"}`))\n break\n case \"error\":\n clearTimeout(timeout)\n socket.off(\"message\", onMessage)\n reject(new Error(`Server error: ${(msg.args as { error?: string | number }).error ?? \"unknown\"}`))\n break\n }\n }\n\n const onDisconnect = (): void => {\n if (!playerLoaded || !roomJoined) {\n clearTimeout(timeout)\n reject(new Error(\"Disconnected before fully loaded\"))\n }\n }\n\n socket.on(\"message\", onMessage)\n socket.once(\"disconnect\", onDisconnect)\n })\n }\n\n on<K extends keyof ServerMessages>(event: K, listener: ServerMessageHandler<K>): this\n on(event: string, listener: (...args: unknown[]) => void): this\n on(event: string, listener: (...args: unknown[]) => void): this {\n return super.on(event, listener)\n }\n\n off<K extends keyof ServerMessages>(event: K, listener: ServerMessageHandler<K>): this\n off(event: string, listener: (...args: unknown[]) => void): this\n off(event: string, listener: (...args: unknown[]) => void): this {\n return super.off(event, listener)\n }\n\n once<K extends keyof ServerMessages>(event: K, listener: ServerMessageHandler<K>): this\n once(event: string, listener: (...args: unknown[]) => void): this\n once(event: string, listener: (...args: unknown[]) => void): this {\n return super.once(event, listener)\n }\n\n emit<K extends keyof ServerMessages>(event: K, args: ServerMessages[K]): boolean\n emit(event: string, ...args: unknown[]): boolean\n emit(event: string, ...args: unknown[]): boolean {\n return super.emit(event, ...args)\n }\n\n sendMessage(message: string): void { this.adapter.sendMessage(message) }\n sendEmote(emote: number): void { this.adapter.sendEmote(emote) }\n sendSafe(safe: number): void { this.adapter.sendSafe(safe) }\n walk(x: number, y: number): void { this.adapter.walk(x, y) }\n sendFrame(frame: number, set?: boolean): void { this.adapter.sendFrame(frame, set) }\n snowball(x: number, y: number): void { this.adapter.snowball(x, y) }\n joinRoom(room: number, x?: number, y?: number): void { this.adapter.joinRoom(room, x, y) }\n addItem(item: number): void { this.adapter.addItem(item) }\n equipColor(item: number): void { this.adapter.equipColor(item) }\n equipHead(item: number): void { this.adapter.equipHead(item) }\n equipFace(item: number): void { this.adapter.equipFace(item) }\n equipNeck(item: number): void { this.adapter.equipNeck(item) }\n equipBody(item: number): void { this.adapter.equipBody(item) }\n equipHand(item: number): void { this.adapter.equipHand(item) }\n equipFeet(item: number): void { this.adapter.equipFeet(item) }\n equipFlag(item: number): void { this.adapter.equipFlag(item) }\n equipPhoto(item: number): void { this.adapter.equipPhoto(item) }\n buddyRequest(id: number): void { this.adapter.buddyRequest(id) }\n buddyAccept(id: number): void { this.adapter.buddyAccept(id) }\n buddyReject(id: number): void { this.adapter.buddyReject(id) }\n buddyRequestSeen(id: number): void { this.adapter.buddyRequestSeen(id) }\n getBuddy(id: number, type: \"buddies\" | \"buddyRequests\"): void { this.adapter.getBuddy(id, type) }\n removeBuddy(id: number): void { this.adapter.removeBuddy(id) }\n addIgnore(id: number): void { this.adapter.addIgnore(id) }\n removeIgnore(id: number): void { this.adapter.removeIgnore(id) }\n getPlayer(id: number): void { this.adapter.getPlayer(id) }\n getAllSlots(): void { this.adapter.getAllSlots() }\n getMascots(): void { this.adapter.getMascots() }\n sendPostcard(userId: number, cardId: string): void { this.adapter.sendPostcard(userId, cardId) }\n getStamps(userId: number): void { this.adapter.getStamps(userId) }\n getPostcards(): void { this.adapter.getPostcards() }\n getIglooOpen(igloo: number): void { this.adapter.getIglooOpen(igloo) }\n joinIgloo(igloo: number, x?: number, y?: number): void { this.adapter.joinIgloo(igloo, x, y) }\n gameOver(coins: number): void { this.adapter.gameOver(coins) }\n collectStamp(stamp: number): void { this.adapter.collectStamp(stamp) }\n\n sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n }\n\n disconnect(): void {\n this.log?.(\"[disconnect] closing connection\")\n this.adapter.disconnect()\n this.cleanup()\n }\n\n private cleanup(): void {\n this.connected = false\n this.player = null\n this.room = null\n this.users.clear()\n }\n\n private handleMessage(msg: MessagePayload): void {\n const { action, args } = msg\n\n switch (action) {\n case \"load_player\": {\n const user = args.user as PlayerData\n user.coins = args.coins as number ?? 0\n user.inventory = args.inventory as number[] ?? []\n user.furniture = args.furniture as unknown[] ?? []\n user.flooring = args.flooring as unknown[] ?? []\n user.rank = args.rank as number ?? 0\n this.player = user\n this.log?.(\"[load_player]\", user.username, `id=${user.id}`, `coins=${user.coins}`, `inventory=${user.inventory.length}`)\n break\n }\n case \"join_room\": {\n const room = args.room as number\n const users = args.users as RoomUser[]\n this.room = room\n this.users.clear()\n for (const user of users) {\n this.users.set(user.id, user)\n }\n this.log?.(\"[join_room]\", `room=${room}`, `users=${users.length}`)\n break\n }\n case \"add_player\": {\n const user = args.user as RoomUser\n this.users.set(user.id, user)\n this.log?.(\"[add_player]\", user.username, `id=${user.id}`)\n break\n }\n case \"remove_player\": {\n const id = args.user as number\n this.users.delete(id)\n this.log?.(\"[remove_player]\", `id=${id}`)\n break\n }\n case \"send_position\": {\n const id = args.id as number\n const user = this.users.get(id)\n if (user) {\n user.x = args.x as number\n user.y = args.y as number\n }\n break\n }\n case \"send_frame\": {\n const id = args.id as number\n const user = this.users.get(id)\n if (user) {\n user.frame = args.frame as number\n }\n break\n }\n case \"update_player\": {\n const id = args.id as number\n const slot = args.slot as string\n const item = args.item as number\n const user = this.users.get(id)\n if (user && slot in user) {\n (user as Record<string, unknown>)[slot] = item\n }\n break\n }\n case \"kick\": {\n const reason = (args as { reason?: string }).reason ?? \"unknown\"\n this.log?.(\"[kick]\", reason)\n this.cleanup()\n break\n }\n case \"close_with_error\": {\n const error = (args as { error?: string }).error ?? \"unknown\"\n this.log?.(\"[kick]\", error)\n this.cleanup()\n break\n }\n default: {\n this.log?.(`[${action}]`, JSON.stringify(args))\n break\n }\n }\n\n const eventName = action === \"error\" ? \"server_error\" : action\n this.emit(eventName, args)\n }\n}\n","import { io, type Socket } from \"socket.io-client\"\nimport msgpackParser from \"socket.io-msgpack-parser\"\nimport type { LoginOptions, LoginResult, QueueUpdate, ServerInfo, TokenLoginOptions } from \"../types/adapter-types.js\"\nimport { BaseAdapter, type ConnectOptions } from \"./base-adapter.js\"\n\nconst BASE_URL = \"wss://play.cpjourney.net\"\nconst DEFAULT_SECRET = \"skip\"\n\ntype LoginResponse = {\n success: boolean\n username: string\n key: string\n populations: Record<string, number>\n moderator: boolean\n buddyWorlds: string[]\n}\n\ntype GameAuthResponse = {\n success: boolean\n token?: string\n}\n\ntype ServerMessage = {\n action: string\n args: Record<string, unknown>\n}\n\nexport class CpjourneyAdapter extends BaseAdapter {\n readonly id = \"CPJourney\"\n\n async login(options: LoginOptions | TokenLoginOptions): Promise<LoginResult> {\n const loginSocket = this.createSocket(\"/world/login/\")\n\n const result = await new Promise<LoginResult>((resolve, reject) => {\n const timeout = setTimeout(() => {\n loginSocket.disconnect()\n reject(new Error(\"Login timed out\"))\n }, 10_000)\n\n loginSocket.on(\"connect\", () => {\n const secret = options.secret ?? DEFAULT_SECRET\n const args = \"token\" in options\n ? { username: options.username, token: options.token, secret }\n : { username: options.username, password: options.password, secret }\n\n loginSocket.emit(\"message\", { action: \"login\", args })\n })\n\n loginSocket.on(\"message\", (msg: ServerMessage) => {\n if (msg.action !== \"login\") return\n\n clearTimeout(timeout)\n loginSocket.disconnect()\n\n const response = msg.args as LoginResponse\n\n if (!response.success) {\n reject(new Error(\"Login failed\"))\n return\n }\n\n const servers: ServerInfo[] = Object.entries(response.populations).map(\n ([name, population]) => ({ name, population })\n )\n\n resolve({\n servers,\n key: response.key,\n username: response.username,\n moderator: response.moderator,\n buddyWorlds: response.buddyWorlds ?? [],\n })\n })\n\n loginSocket.on(\"connect_error\", (err: Error) => {\n clearTimeout(timeout)\n loginSocket.disconnect()\n reject(new Error(`Login connection failed: ${err.message}`))\n })\n })\n\n return result\n }\n\n async connect(serverName: string, loginResult: LoginResult, options?: ConnectOptions): Promise<Socket> {\n const gameSocket = this.createSocket(`/world/${serverName.toLowerCase()}/`)\n this.socket = gameSocket\n\n await new Promise<void>((resolve, reject) => {\n let authSent = false\n\n gameSocket.on(\"connect\", () => {\n gameSocket.emit(\"message\", {\n action: \"game_auth\",\n args: {\n username: loginResult.username,\n key: loginResult.key,\n createToken: false,\n joinInvis: false,\n takeoverMascot: false,\n token: \"\",\n },\n })\n })\n\n gameSocket.on(\"message\", (msg: ServerMessage) => {\n switch (msg.action) {\n case \"wait_queue_update\": {\n options?.onQueueUpdate?.(msg.args as QueueUpdate)\n break\n }\n case \"game_auth\": {\n if (authSent) break\n authSent = true\n\n const response = msg.args as GameAuthResponse\n if (!response.success) {\n gameSocket.disconnect()\n reject(new Error(\"Game auth failed\"))\n return\n }\n\n gameSocket.emit(\"message\", { action: \"join_server\", args: {} })\n resolve()\n break\n }\n }\n })\n\n gameSocket.on(\"connect_error\", (err: Error) => {\n gameSocket.disconnect()\n reject(new Error(`Game connection failed: ${err.message}`))\n })\n })\n\n return gameSocket\n }\n\n send(action: string, args: Record<string, unknown>): void {\n if (!this.socket) throw new Error(\"Not connected\")\n this.socket.emit(\"message\", { action, args })\n }\n\n disconnect(): void {\n this.socket?.disconnect()\n this.socket = null\n }\n\n private createSocket(path: string): Socket {\n return io(BASE_URL, {\n path,\n parser: msgpackParser,\n transports: [\"polling\", \"websocket\"],\n reconnection: false,\n })\n }\n}\n","import type { Socket } from \"socket.io-client\"\nimport type { LoginOptions, LoginResult, QueueUpdate, TokenLoginOptions } from \"../types/adapter-types.js\"\n\nexport type ConnectOptions = {\n onQueueUpdate?: (update: QueueUpdate) => void\n}\n\nexport abstract class BaseAdapter {\n abstract readonly id: string\n protected socket: Socket | null = null\n\n abstract login(options: LoginOptions | TokenLoginOptions): Promise<LoginResult>\n abstract connect(serverName: string, loginResult: LoginResult, options?: ConnectOptions): Promise<Socket>\n abstract disconnect(): void\n abstract send(action: string, args: Record<string, unknown>): void\n\n sendMessage(message: string): void {\n this.send(\"send_message\", { message })\n }\n\n sendEmote(emote: number): void {\n this.send(\"send_emote\", { emote })\n }\n\n sendSafe(safe: number): void {\n this.send(\"send_safe\", { safe })\n }\n\n walk(x: number, y: number): void {\n this.send(\"send_position\", { x, y })\n }\n\n sendFrame(frame: number, set?: boolean): void {\n this.send(\"send_frame\", { frame, set })\n }\n\n snowball(x: number, y: number): void {\n this.send(\"snowball\", { x, y })\n }\n\n joinRoom(room: number, x?: number, y?: number): void {\n this.send(\"join_room\", { room, x: x ?? 0, y: y ?? 0 })\n }\n\n addItem(item: number): void {\n this.send(\"add_item\", { item })\n }\n\n equipColor(item: number): void {\n this.send(\"update_color\", { item })\n }\n\n equipHead(item: number): void {\n this.send(\"update_head\", { item })\n }\n\n equipFace(item: number): void {\n this.send(\"update_face\", { item })\n }\n\n equipNeck(item: number): void {\n this.send(\"update_neck\", { item })\n }\n\n equipBody(item: number): void {\n this.send(\"update_body\", { item })\n }\n\n equipHand(item: number): void {\n this.send(\"update_hand\", { item })\n }\n\n equipFeet(item: number): void {\n this.send(\"update_feet\", { item })\n }\n\n equipFlag(item: number): void {\n this.send(\"update_flag\", { item })\n }\n\n equipPhoto(item: number): void {\n this.send(\"update_photo\", { item })\n }\n\n buddyRequest(id: number): void {\n this.send(\"buddy_request\", { id })\n }\n\n buddyAccept(id: number): void {\n this.send(\"buddy_accept\", { id })\n }\n\n buddyReject(id: number): void {\n this.send(\"buddy_reject\", { id })\n }\n\n buddyRequestSeen(id: number): void {\n this.send(\"buddy_request_seen\", { id })\n }\n\n getBuddy(id: number, type: \"buddies\" | \"buddyRequests\"): void {\n this.send(\"get_buddy\", { id, type })\n }\n\n removeBuddy(id: number): void {\n this.send(\"remove_buddy\", { id })\n }\n\n addIgnore(id: number): void {\n this.send(\"ignore_add\", { id })\n }\n\n removeIgnore(id: number): void {\n this.send(\"ignore_remove\", { id })\n }\n\n getPlayer(id: number): void {\n this.send(\"get_player\", { id })\n }\n\n getAllSlots(): void {\n this.send(\"get_all_slots\", {})\n }\n\n getMascots(): void {\n this.send(\"get_mascots\", {})\n }\n\n sendPostcard(userId: number, cardId: string): void {\n this.send(\"send_postcard\", { userId, cardId })\n }\n\n getStamps(userId: number): void {\n this.send(\"get_stamps\", { userId })\n }\n\n getPostcards(): void {\n this.send(\"get_postcards\", {})\n }\n\n getIglooOpen(igloo: number): void {\n this.send(\"get_igloo_open\", { igloo })\n }\n\n joinIgloo(igloo: number, x?: number, y?: number): void {\n this.send(\"join_igloo\", { igloo, x: x ?? 0, y: y ?? 0 })\n }\n\n gameOver(coins: number): void {\n this.send(\"game_over\", { coins })\n }\n\n collectStamp(stamp: number): void {\n this.send(\"collect_stamp\", { stamp })\n }\n}\n","import { io, type Socket } from \"socket.io-client\"\nimport msgpackParser from \"socket.io-msgpack-parser\"\nimport type { LoginOptions, LoginResult, QueueUpdate, ServerInfo, TokenLoginOptions } from \"../types/adapter-types.js\"\nimport { BaseAdapter, type ConnectOptions } from \"./base-adapter.js\"\n\nconst LOGIN_URL = \"https://api.cplegacy.com/login\"\nconst TOKEN_LOGIN_URL = \"https://api.cplegacy.com/token_login\"\n\ntype LoginResponse = {\n success: boolean\n username: string\n key: string\n populations: Record<string, number>\n requires2FA: boolean\n message?: string\n wantedVersion?: string\n}\n\ntype GameAuthResponse = {\n success: boolean\n}\n\n/**\n * Wraps a CPLegacy socket to normalize its positional message format\n * `(\"message\", action, args)` into the `{ action, args }` envelope\n * that the Client class expects.\n */\nfunction wrapSocket(raw: Socket): Socket {\n const original = raw.on.bind(raw)\n\n raw.on = function (event: string, listener: (...args: unknown[]) => void) {\n if (event === \"message\") {\n return original(event, (action: unknown, args: unknown) => {\n listener({ action, args: args ?? {} })\n })\n }\n return original(event, listener)\n } as typeof raw.on\n\n return raw\n}\n\nexport class CplegacyAdapter extends BaseAdapter {\n readonly id = \"CPLegacy\"\n private version = \"\"\n\n async login(options: LoginOptions | TokenLoginOptions): Promise<LoginResult> {\n const url = \"token\" in options ? TOKEN_LOGIN_URL : LOGIN_URL\n const body: Record<string, unknown> = \"token\" in options\n ? { username: options.username, token: options.token }\n : { username: options.username, password: options.password, version: this.version }\n\n let data = await this.postLogin(url, body)\n\n // Version negotiation: server returns wantedVersion when ours is stale/empty\n if (!data.success && data.wantedVersion) {\n this.version = data.wantedVersion\n body.version = this.version\n data = await this.postLogin(url, body)\n }\n\n if (!data.success) {\n throw new Error(`Login failed: ${data.message ?? \"unknown error\"}`)\n }\n\n const servers: ServerInfo[] = Object.entries(data.populations ?? {}).map(\n ([name, population]) => ({ name, population })\n )\n\n return {\n servers,\n key: data.key,\n username: data.username,\n moderator: false,\n buddyWorlds: [],\n }\n }\n\n async connect(serverName: string, loginResult: LoginResult, options?: ConnectOptions): Promise<Socket> {\n const wsUrl = `wss://${serverName.toLowerCase()}.server.cplegacy.com`\n const rawSocket = io(wsUrl, {\n path: \"/socket.io/\",\n parser: msgpackParser,\n transports: [\"websocket\"],\n reconnection: false,\n })\n this.socket = rawSocket\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n rawSocket.disconnect()\n reject(new Error(\"Game connection timed out\"))\n }, 15_000)\n\n rawSocket.on(\"connect\", () => {\n rawSocket.emit(\"message\", \"game_auth\", {\n username: loginResult.username,\n key: loginResult.key,\n createToken: false,\n token: \"\",\n })\n })\n\n rawSocket.on(\"message\", (action: string, args: Record<string, unknown>) => {\n switch (action) {\n case \"wait_queue_update\": {\n options?.onQueueUpdate?.(args as unknown as QueueUpdate)\n break\n }\n case \"game_auth\": {\n const response = args as unknown as GameAuthResponse\n if (!response.success) {\n clearTimeout(timeout)\n rawSocket.disconnect()\n reject(new Error(\"Game auth failed\"))\n return\n }\n\n // CPLegacy requires explicitly requesting load_player before join_server\n rawSocket.emit(\"message\", \"load_player\", {})\n rawSocket.emit(\"message\", \"join_server\", {})\n clearTimeout(timeout)\n resolve()\n break\n }\n }\n })\n\n rawSocket.on(\"connect_error\", (err: Error) => {\n clearTimeout(timeout)\n rawSocket.disconnect()\n reject(new Error(`Game connection failed: ${err.message}`))\n })\n })\n\n // Return wrapped socket so Client receives normalized { action, args } messages\n return wrapSocket(rawSocket)\n }\n\n send(action: string, args: Record<string, unknown>): void {\n if (!this.socket) throw new Error(\"Not connected\")\n this.socket.emit(\"message\", action, args)\n }\n\n disconnect(): void {\n this.socket?.disconnect()\n this.socket = null\n }\n\n private async postLogin(url: string, body: Record<string, unknown>): Promise<LoginResponse> {\n const resp = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify(body),\n })\n\n return resp.json() as Promise<LoginResponse>\n }\n}\n","import type { BaseAdapter } from \"./base-adapter.js\"\nimport { CpjourneyAdapter } from \"./cpjourney-adapter.js\"\nimport { CplegacyAdapter } from \"./cplegacy-adapter.js\"\n\nconst ADAPTERS = {\n CPJourney: CpjourneyAdapter,\n CPLegacy: CplegacyAdapter,\n} as const\n\nexport type AdapterName = keyof typeof ADAPTERS\n\nexport function createAdapter(name: AdapterName): BaseAdapter {\n return new ADAPTERS[name]()\n}\n"],"mappings":"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","names":["EventEmitter","io","msgpackParser","BaseAdapter","message","emote","safe","x","y","frame","set","room","item","id","type","userId","cardId","igloo","coins","stamp","BASE_URL","DEFAULT_SECRET","CpjourneyAdapter","BaseAdapter","options","loginSocket","resolve","reject","timeout","secret","args","msg","response","servers","name","population","err","serverName","loginResult","gameSocket","authSent","action","path","io","msgpackParser","io","msgpackParser","LOGIN_URL","TOKEN_LOGIN_URL","wrapSocket","raw","original","event","listener","action","args","CplegacyAdapter","BaseAdapter","options","url","body","data","name","population","serverName","loginResult","wsUrl","rawSocket","io","msgpackParser","resolve","reject","timeout","err","ADAPTERS","CpjourneyAdapter","CplegacyAdapter","createAdapter","name","isMessagePayload","msg","Client","EventEmitter","server","options","createAdapter","serverName","connectOptions","update","socket","resolve","reject","timeout","playerLoaded","roomJoined","checkReady","onMessage","onDisconnect","event","listener","args","message","emote","safe","x","y","frame","set","room","item","id","type","userId","cardId","igloo","coins","stamp","ms","action","user","users","slot","reason","error","eventName"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/adapters/cpjourney-adapter.ts","../src/adapters/base-adapter.ts","../src/adapters/cplegacy-adapter.ts","../src/adapters/newcp-adapter.ts","../src/adapters/index.ts"],"sourcesContent":["import { EventEmitter } from \"node:events\"\nimport { createAdapter, type AdapterName } from \"./adapters/index.js\"\nimport type { BaseAdapter, ConnectOptions } from \"./adapters/base-adapter.js\"\nimport type { LoginOptions, LoginResult, QueueUpdate, ServerInfo, TokenLoginOptions } from \"./types/adapter-types.js\"\nimport type { ServerMessages } from \"./types/message-types.js\"\nimport type { PlayerData, RoomUser } from \"./types/player-types.js\"\n\ntype ServerMessageHandler<K extends keyof ServerMessages> = (args: ServerMessages[K]) => void\n\nexport type LogFn = (message: string, ...args: unknown[]) => void\n\nexport type ClientOptions = {\n debug?: boolean | LogFn\n}\n\ntype MessagePayload = {\n action: string\n args: Record<string, unknown>\n}\n\nfunction isMessagePayload(msg: unknown): msg is MessagePayload {\n return typeof msg === \"object\" && msg !== null && \"action\" in msg && \"args\" in msg\n}\n\nexport class Client extends EventEmitter {\n player: PlayerData | null = null\n room: number | null = null\n users: Map<number, RoomUser> = new Map()\n connected = false\n\n private adapter: BaseAdapter\n private loginResult: LoginResult | null = null\n private log: LogFn | null = null\n\n constructor(server: AdapterName, options?: ClientOptions) {\n super()\n this.adapter = createAdapter(server)\n\n if (options?.debug) {\n this.log = typeof options.debug === \"function\"\n ? options.debug\n : console.log.bind(console)\n }\n }\n\n async login(options: LoginOptions | TokenLoginOptions): Promise<ServerInfo[]> {\n this.log?.(\"[login] logging in as\", options.username)\n this.loginResult = await this.adapter.login(options)\n this.log?.(\"[login] success —\", this.loginResult.servers.length, \"servers\")\n return this.loginResult.servers\n }\n\n async connect(serverName: string, options?: ConnectOptions): Promise<void> {\n if (!this.loginResult) throw new Error(\"Must call login() first\")\n\n this.log?.(\"[connect] joining\", serverName)\n\n const connectOptions: ConnectOptions = {\n ...options,\n onQueueUpdate: (update: QueueUpdate) => {\n this.log?.(\"[queue]\", `#${update.position}/${update.queueLength}`)\n this.emit(\"wait_queue_update\", update)\n options?.onQueueUpdate?.(update)\n },\n }\n\n const socket = await this.adapter.connect(serverName, this.loginResult, connectOptions)\n\n socket.on(\"message\", (msg: unknown) => {\n if (!isMessagePayload(msg)) return\n this.handleMessage(msg)\n })\n\n socket.on(\"disconnect\", () => {\n this.log?.(\"[disconnect] connection lost\")\n this.cleanup()\n this.emit(\"disconnect\")\n })\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(\"Waiting for load_player timed out\"))\n }, 10_000)\n\n let playerLoaded = false\n let roomJoined = false\n\n const checkReady = (): void => {\n if (playerLoaded && roomJoined) {\n clearTimeout(timeout)\n this.connected = true\n resolve()\n }\n }\n\n const onMessage = (msg: unknown): void => {\n if (!isMessagePayload(msg)) return\n switch (msg.action) {\n case \"load_player\":\n playerLoaded = true\n checkReady()\n break\n case \"join_room\":\n roomJoined = true\n checkReady()\n break\n case \"kick\":\n clearTimeout(timeout)\n socket.off(\"message\", onMessage)\n reject(new Error(`Kicked: ${(msg.args as { reason?: string }).reason ?? \"unknown\"}`))\n break\n case \"close_with_error\":\n clearTimeout(timeout)\n socket.off(\"message\", onMessage)\n reject(new Error(`Kicked: ${(msg.args as { error?: string }).error ?? \"unknown\"}`))\n break\n case \"error\":\n clearTimeout(timeout)\n socket.off(\"message\", onMessage)\n reject(new Error(`Server error: ${(msg.args as { error?: string | number }).error ?? \"unknown\"}`))\n break\n }\n }\n\n const onDisconnect = (): void => {\n if (!playerLoaded || !roomJoined) {\n clearTimeout(timeout)\n reject(new Error(\"Disconnected before fully loaded\"))\n }\n }\n\n socket.on(\"message\", onMessage)\n socket.once(\"disconnect\", onDisconnect)\n })\n }\n\n on<K extends keyof ServerMessages>(event: K, listener: ServerMessageHandler<K>): this\n on(event: string, listener: (...args: unknown[]) => void): this\n on(event: string, listener: (...args: unknown[]) => void): this {\n return super.on(event, listener)\n }\n\n off<K extends keyof ServerMessages>(event: K, listener: ServerMessageHandler<K>): this\n off(event: string, listener: (...args: unknown[]) => void): this\n off(event: string, listener: (...args: unknown[]) => void): this {\n return super.off(event, listener)\n }\n\n once<K extends keyof ServerMessages>(event: K, listener: ServerMessageHandler<K>): this\n once(event: string, listener: (...args: unknown[]) => void): this\n once(event: string, listener: (...args: unknown[]) => void): this {\n return super.once(event, listener)\n }\n\n emit<K extends keyof ServerMessages>(event: K, args: ServerMessages[K]): boolean\n emit(event: string, ...args: unknown[]): boolean\n emit(event: string, ...args: unknown[]): boolean {\n return super.emit(event, ...args)\n }\n\n sendMessage(message: string): void { this.adapter.sendMessage(message) }\n sendEmote(emote: number): void { this.adapter.sendEmote(emote) }\n sendSafe(safe: number): void { this.adapter.sendSafe(safe) }\n walk(x: number, y: number): void { this.adapter.walk(x, y) }\n sendFrame(frame: number, set?: boolean): void { this.adapter.sendFrame(frame, set) }\n snowball(x: number, y: number): void { this.adapter.snowball(x, y) }\n joinRoom(room: number, x?: number, y?: number): void { this.adapter.joinRoom(room, x, y) }\n addItem(item: number): void { this.adapter.addItem(item) }\n equipColor(item: number): void { this.adapter.equipColor(item) }\n equipHead(item: number): void { this.adapter.equipHead(item) }\n equipFace(item: number): void { this.adapter.equipFace(item) }\n equipNeck(item: number): void { this.adapter.equipNeck(item) }\n equipBody(item: number): void { this.adapter.equipBody(item) }\n equipHand(item: number): void { this.adapter.equipHand(item) }\n equipFeet(item: number): void { this.adapter.equipFeet(item) }\n equipFlag(item: number): void { this.adapter.equipFlag(item) }\n equipPhoto(item: number): void { this.adapter.equipPhoto(item) }\n buddyRequest(id: number): void { this.adapter.buddyRequest(id) }\n buddyAccept(id: number): void { this.adapter.buddyAccept(id) }\n buddyReject(id: number): void { this.adapter.buddyReject(id) }\n buddyRequestSeen(id: number): void { this.adapter.buddyRequestSeen(id) }\n getBuddy(id: number, type: \"buddies\" | \"buddyRequests\"): void { this.adapter.getBuddy(id, type) }\n removeBuddy(id: number): void { this.adapter.removeBuddy(id) }\n addIgnore(id: number): void { this.adapter.addIgnore(id) }\n removeIgnore(id: number): void { this.adapter.removeIgnore(id) }\n getPlayer(id: number): void { this.adapter.getPlayer(id) }\n getAllSlots(): void { this.adapter.getAllSlots() }\n getMascots(): void { this.adapter.getMascots() }\n sendPostcard(userId: number, cardId: string): void { this.adapter.sendPostcard(userId, cardId) }\n getStamps(userId: number): void { this.adapter.getStamps(userId) }\n getPostcards(): void { this.adapter.getPostcards() }\n getIglooOpen(igloo: number): void { this.adapter.getIglooOpen(igloo) }\n joinIgloo(igloo: number, x?: number, y?: number): void { this.adapter.joinIgloo(igloo, x, y) }\n gameOver(coins: number): void { this.adapter.gameOver(coins) }\n collectStamp(stamp: number): void { this.adapter.collectStamp(stamp) }\n\n sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n }\n\n disconnect(): void {\n this.log?.(\"[disconnect] closing connection\")\n this.adapter.disconnect()\n this.cleanup()\n }\n\n private cleanup(): void {\n this.connected = false\n this.player = null\n this.room = null\n this.users.clear()\n }\n\n private handleMessage(msg: MessagePayload): void {\n const { action, args } = msg\n\n switch (action) {\n case \"load_player\": {\n const user = args.user as PlayerData\n user.coins = args.coins as number ?? 0\n user.inventory = args.inventory as number[] ?? []\n user.furniture = args.furniture as unknown[] ?? []\n user.flooring = args.flooring as unknown[] ?? []\n user.rank = args.rank as number ?? 0\n this.player = user\n this.log?.(\"[load_player]\", user.username, `id=${user.id}`, `coins=${user.coins}`, `inventory=${user.inventory.length}`)\n break\n }\n case \"join_room\": {\n const room = args.room as number\n const users = args.users as RoomUser[]\n this.room = room\n this.users.clear()\n for (const user of users) {\n this.users.set(user.id, user)\n }\n this.log?.(\"[join_room]\", `room=${room}`, `users=${users.length}`)\n break\n }\n case \"add_player\": {\n const user = args.user as RoomUser\n this.users.set(user.id, user)\n this.log?.(\"[add_player]\", user.username, `id=${user.id}`)\n break\n }\n case \"remove_player\": {\n const id = args.user as number\n this.users.delete(id)\n this.log?.(\"[remove_player]\", `id=${id}`)\n break\n }\n case \"send_position\": {\n const id = args.id as number\n const user = this.users.get(id)\n if (user) {\n user.x = args.x as number\n user.y = args.y as number\n }\n break\n }\n case \"send_frame\": {\n const id = args.id as number\n const user = this.users.get(id)\n if (user) {\n user.frame = args.frame as number\n }\n break\n }\n case \"update_player\": {\n const id = args.id as number\n const slot = args.slot as string\n const item = args.item as number\n const user = this.users.get(id)\n if (user && slot in user) {\n (user as Record<string, unknown>)[slot] = item\n }\n break\n }\n case \"kick\": {\n const reason = (args as { reason?: string }).reason ?? \"unknown\"\n this.log?.(\"[kick]\", reason)\n this.cleanup()\n break\n }\n case \"close_with_error\": {\n const error = (args as { error?: string }).error ?? \"unknown\"\n this.log?.(\"[kick]\", error)\n this.cleanup()\n break\n }\n default: {\n this.log?.(`[${action}]`, JSON.stringify(args))\n break\n }\n }\n\n const eventName = action === \"error\" ? \"server_error\" : action\n this.emit(eventName, args)\n }\n}\n","import { io, type Socket } from \"socket.io-client\"\nimport msgpackParser from \"socket.io-msgpack-parser\"\nimport type { LoginOptions, LoginResult, QueueUpdate, ServerInfo, TokenLoginOptions } from \"../types/adapter-types.js\"\nimport { BaseAdapter, type ConnectOptions } from \"./base-adapter.js\"\n\nconst BASE_URL = \"wss://play.cpjourney.net\"\nconst DEFAULT_SECRET = \"skip\"\n\ntype LoginResponse = {\n success: boolean\n username: string\n key: string\n populations: Record<string, number>\n moderator: boolean\n buddyWorlds: string[]\n}\n\ntype GameAuthResponse = {\n success: boolean\n token?: string\n}\n\ntype ServerMessage = {\n action: string\n args: Record<string, unknown>\n}\n\nexport class CpjourneyAdapter extends BaseAdapter {\n readonly id = \"CPJourney\"\n\n async login(options: LoginOptions | TokenLoginOptions): Promise<LoginResult> {\n const loginSocket = this.createSocket(\"/world/login/\")\n\n const result = await new Promise<LoginResult>((resolve, reject) => {\n const timeout = setTimeout(() => {\n loginSocket.disconnect()\n reject(new Error(\"Login timed out\"))\n }, 10_000)\n\n loginSocket.on(\"connect\", () => {\n const secret = options.secret ?? DEFAULT_SECRET\n const args = \"token\" in options\n ? { username: options.username, token: options.token, secret }\n : { username: options.username, password: options.password, secret }\n\n loginSocket.emit(\"message\", { action: \"login\", args })\n })\n\n loginSocket.on(\"message\", (msg: ServerMessage) => {\n if (msg.action !== \"login\") return\n\n clearTimeout(timeout)\n loginSocket.disconnect()\n\n const response = msg.args as LoginResponse\n\n if (!response.success) {\n reject(new Error(\"Login failed\"))\n return\n }\n\n const servers: ServerInfo[] = Object.entries(response.populations).map(\n ([name, population]) => ({ name, population })\n )\n\n resolve({\n servers,\n key: response.key,\n username: response.username,\n moderator: response.moderator,\n buddyWorlds: response.buddyWorlds ?? [],\n })\n })\n\n loginSocket.on(\"connect_error\", (err: Error) => {\n clearTimeout(timeout)\n loginSocket.disconnect()\n reject(new Error(`Login connection failed: ${err.message}`))\n })\n })\n\n return result\n }\n\n async connect(serverName: string, loginResult: LoginResult, options?: ConnectOptions): Promise<Socket> {\n const gameSocket = this.createSocket(`/world/${serverName.toLowerCase()}/`)\n this.socket = gameSocket\n\n await new Promise<void>((resolve, reject) => {\n let authSent = false\n\n gameSocket.on(\"connect\", () => {\n gameSocket.emit(\"message\", {\n action: \"game_auth\",\n args: {\n username: loginResult.username,\n key: loginResult.key,\n createToken: false,\n joinInvis: false,\n takeoverMascot: false,\n token: \"\",\n },\n })\n })\n\n gameSocket.on(\"message\", (msg: ServerMessage) => {\n switch (msg.action) {\n case \"wait_queue_update\": {\n options?.onQueueUpdate?.(msg.args as QueueUpdate)\n break\n }\n case \"game_auth\": {\n if (authSent) break\n authSent = true\n\n const response = msg.args as GameAuthResponse\n if (!response.success) {\n gameSocket.disconnect()\n reject(new Error(\"Game auth failed\"))\n return\n }\n\n gameSocket.emit(\"message\", { action: \"join_server\", args: {} })\n resolve()\n break\n }\n }\n })\n\n gameSocket.on(\"connect_error\", (err: Error) => {\n gameSocket.disconnect()\n reject(new Error(`Game connection failed: ${err.message}`))\n })\n })\n\n return gameSocket\n }\n\n send(action: string, args: Record<string, unknown>): void {\n if (!this.socket) throw new Error(\"Not connected\")\n this.socket.emit(\"message\", { action, args })\n }\n\n disconnect(): void {\n this.socket?.disconnect()\n this.socket = null\n }\n\n private createSocket(path: string): Socket {\n return io(BASE_URL, {\n path,\n parser: msgpackParser,\n transports: [\"polling\", \"websocket\"],\n reconnection: false,\n })\n }\n}\n","import type { Socket } from \"socket.io-client\"\nimport type { LoginOptions, LoginResult, QueueUpdate, TokenLoginOptions } from \"../types/adapter-types.js\"\n\nexport type ConnectOptions = {\n onQueueUpdate?: (update: QueueUpdate) => void\n}\n\nexport abstract class BaseAdapter {\n abstract readonly id: string\n protected socket: Socket | null = null\n\n abstract login(options: LoginOptions | TokenLoginOptions): Promise<LoginResult>\n abstract connect(serverName: string, loginResult: LoginResult, options?: ConnectOptions): Promise<Socket>\n abstract disconnect(): void\n abstract send(action: string, args: Record<string, unknown>): void\n\n sendMessage(message: string): void {\n this.send(\"send_message\", { message })\n }\n\n sendEmote(emote: number): void {\n this.send(\"send_emote\", { emote })\n }\n\n sendSafe(safe: number): void {\n this.send(\"send_safe\", { safe })\n }\n\n walk(x: number, y: number): void {\n this.send(\"send_position\", { x, y })\n }\n\n sendFrame(frame: number, set?: boolean): void {\n this.send(\"send_frame\", { frame, set })\n }\n\n snowball(x: number, y: number): void {\n this.send(\"snowball\", { x, y })\n }\n\n joinRoom(room: number, x?: number, y?: number): void {\n this.send(\"join_room\", { room, x: x ?? 0, y: y ?? 0 })\n }\n\n addItem(item: number): void {\n this.send(\"add_item\", { item })\n }\n\n equipColor(item: number): void {\n this.send(\"update_color\", { item })\n }\n\n equipHead(item: number): void {\n this.send(\"update_head\", { item })\n }\n\n equipFace(item: number): void {\n this.send(\"update_face\", { item })\n }\n\n equipNeck(item: number): void {\n this.send(\"update_neck\", { item })\n }\n\n equipBody(item: number): void {\n this.send(\"update_body\", { item })\n }\n\n equipHand(item: number): void {\n this.send(\"update_hand\", { item })\n }\n\n equipFeet(item: number): void {\n this.send(\"update_feet\", { item })\n }\n\n equipFlag(item: number): void {\n this.send(\"update_flag\", { item })\n }\n\n equipPhoto(item: number): void {\n this.send(\"update_photo\", { item })\n }\n\n buddyRequest(id: number): void {\n this.send(\"buddy_request\", { id })\n }\n\n buddyAccept(id: number): void {\n this.send(\"buddy_accept\", { id })\n }\n\n buddyReject(id: number): void {\n this.send(\"buddy_reject\", { id })\n }\n\n buddyRequestSeen(id: number): void {\n this.send(\"buddy_request_seen\", { id })\n }\n\n getBuddy(id: number, type: \"buddies\" | \"buddyRequests\"): void {\n this.send(\"get_buddy\", { id, type })\n }\n\n removeBuddy(id: number): void {\n this.send(\"remove_buddy\", { id })\n }\n\n addIgnore(id: number): void {\n this.send(\"ignore_add\", { id })\n }\n\n removeIgnore(id: number): void {\n this.send(\"ignore_remove\", { id })\n }\n\n getPlayer(id: number): void {\n this.send(\"get_player\", { id })\n }\n\n getAllSlots(): void {\n this.send(\"get_all_slots\", {})\n }\n\n getMascots(): void {\n this.send(\"get_mascots\", {})\n }\n\n sendPostcard(userId: number, cardId: string): void {\n this.send(\"send_postcard\", { userId, cardId })\n }\n\n getStamps(userId: number): void {\n this.send(\"get_stamps\", { userId })\n }\n\n getPostcards(): void {\n this.send(\"get_postcards\", {})\n }\n\n getIglooOpen(igloo: number): void {\n this.send(\"get_igloo_open\", { igloo })\n }\n\n joinIgloo(igloo: number, x?: number, y?: number): void {\n this.send(\"join_igloo\", { igloo, x: x ?? 0, y: y ?? 0 })\n }\n\n gameOver(coins: number): void {\n this.send(\"game_over\", { coins })\n }\n\n collectStamp(stamp: number): void {\n this.send(\"collect_stamp\", { stamp })\n }\n}\n","import { io, type Socket } from \"socket.io-client\"\nimport msgpackParser from \"socket.io-msgpack-parser\"\nimport type { LoginOptions, LoginResult, QueueUpdate, ServerInfo, TokenLoginOptions } from \"../types/adapter-types.js\"\nimport { BaseAdapter, type ConnectOptions } from \"./base-adapter.js\"\n\nconst LOGIN_URL = \"https://api.cplegacy.com/login\"\nconst TOKEN_LOGIN_URL = \"https://api.cplegacy.com/token_login\"\n\ntype LoginResponse = {\n success: boolean\n username: string\n key: string\n populations: Record<string, number>\n requires2FA: boolean\n message?: string\n wantedVersion?: string\n}\n\ntype GameAuthResponse = {\n success: boolean\n}\n\n/**\n * Wraps a CPLegacy socket to normalize its positional message format\n * `(\"message\", action, args)` into the `{ action, args }` envelope\n * that the Client class expects.\n */\nfunction wrapSocket(raw: Socket): Socket {\n const original = raw.on.bind(raw)\n\n raw.on = function (event: string, listener: (...args: unknown[]) => void) {\n if (event === \"message\") {\n return original(event, (action: unknown, args: unknown) => {\n listener({ action, args: args ?? {} })\n })\n }\n return original(event, listener)\n } as typeof raw.on\n\n return raw\n}\n\nexport class CplegacyAdapter extends BaseAdapter {\n readonly id = \"CPLegacy\"\n private version = \"\"\n\n async login(options: LoginOptions | TokenLoginOptions): Promise<LoginResult> {\n const url = \"token\" in options ? TOKEN_LOGIN_URL : LOGIN_URL\n const body: Record<string, unknown> = \"token\" in options\n ? { username: options.username, token: options.token }\n : { username: options.username, password: options.password, version: this.version }\n\n let data = await this.postLogin(url, body)\n\n // Version negotiation: server returns wantedVersion when ours is stale/empty\n if (!data.success && data.wantedVersion) {\n this.version = data.wantedVersion\n body.version = this.version\n data = await this.postLogin(url, body)\n }\n\n if (!data.success) {\n throw new Error(`Login failed: ${data.message ?? \"unknown error\"}`)\n }\n\n const servers: ServerInfo[] = Object.entries(data.populations ?? {}).map(\n ([name, population]) => ({ name, population })\n )\n\n return {\n servers,\n key: data.key,\n username: data.username,\n moderator: false,\n buddyWorlds: [],\n }\n }\n\n async connect(serverName: string, loginResult: LoginResult, options?: ConnectOptions): Promise<Socket> {\n const wsUrl = `wss://${serverName.toLowerCase()}.server.cplegacy.com`\n const rawSocket = io(wsUrl, {\n path: \"/socket.io/\",\n parser: msgpackParser,\n transports: [\"websocket\"],\n reconnection: false,\n })\n this.socket = rawSocket\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n rawSocket.disconnect()\n reject(new Error(\"Game connection timed out\"))\n }, 15_000)\n\n rawSocket.on(\"connect\", () => {\n rawSocket.emit(\"message\", \"game_auth\", {\n username: loginResult.username,\n key: loginResult.key,\n createToken: false,\n token: \"\",\n })\n })\n\n rawSocket.on(\"message\", (action: string, args: Record<string, unknown>) => {\n switch (action) {\n case \"wait_queue_update\": {\n options?.onQueueUpdate?.(args as unknown as QueueUpdate)\n break\n }\n case \"game_auth\": {\n const response = args as unknown as GameAuthResponse\n if (!response.success) {\n clearTimeout(timeout)\n rawSocket.disconnect()\n reject(new Error(\"Game auth failed\"))\n return\n }\n\n // CPLegacy requires explicitly requesting load_player before join_server\n rawSocket.emit(\"message\", \"load_player\", {})\n rawSocket.emit(\"message\", \"join_server\", {})\n clearTimeout(timeout)\n resolve()\n break\n }\n }\n })\n\n rawSocket.on(\"connect_error\", (err: Error) => {\n clearTimeout(timeout)\n rawSocket.disconnect()\n reject(new Error(`Game connection failed: ${err.message}`))\n })\n })\n\n // Return wrapped socket so Client receives normalized { action, args } messages\n return wrapSocket(rawSocket)\n }\n\n send(action: string, args: Record<string, unknown>): void {\n if (!this.socket) throw new Error(\"Not connected\")\n this.socket.emit(\"message\", action, args)\n }\n\n disconnect(): void {\n this.socket?.disconnect()\n this.socket = null\n }\n\n private async postLogin(url: string, body: Record<string, unknown>): Promise<LoginResponse> {\n const resp = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify(body),\n })\n\n return resp.json() as Promise<LoginResponse>\n }\n}\n","import { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\"\nimport { io, type Socket } from \"socket.io-client\"\nimport nacl from \"tweetnacl\"\nimport type { LoginOptions, LoginResult, QueueUpdate, ServerInfo, TokenLoginOptions } from \"../types/adapter-types.js\"\nimport { BaseAdapter, type ConnectOptions } from \"./base-adapter.js\"\n\nconst CRUMBS_URL = \"https://media8.newcp.net/assets/media/crumbs/en/crumbs.json\"\n\ntype WorldConfig = {\n id?: number\n host: string\n path: string\n login?: boolean\n}\n\ntype CrumbsWorlds = Record<string, WorldConfig>\n\ntype LoginResponse = {\n success: boolean\n username: string\n key: string\n populations: Record<string, number>\n moderator: boolean\n buddyWorlds: string[]\n}\n\ntype GameAuthResponse = {\n success: boolean\n token?: string\n}\n\nclass Encryptor {\n private aesKey: Buffer | null = null\n private keypair = nacl.box.keyPair()\n\n get publicKey(): string {\n return Buffer.from(this.keypair.publicKey).toString(\"base64\")\n }\n\n get encrypted(): boolean {\n return this.aesKey !== null\n }\n\n acquireKey(encryptedB64: string, serverPubKeyB64: string): string | null {\n const data = Buffer.from(encryptedB64, \"base64\")\n const serverPubKey = Buffer.from(serverPubKeyB64, \"base64\")\n const nonce = data.subarray(0, nacl.box.nonceLength)\n const ciphertext = data.subarray(nacl.box.nonceLength)\n const plaintext = nacl.box.open(\n new Uint8Array(ciphertext),\n new Uint8Array(nonce),\n new Uint8Array(serverPubKey),\n this.keypair.secretKey,\n )\n return plaintext ? new TextDecoder().decode(plaintext) : null\n }\n\n setKey(keyString: string): void {\n this.aesKey = Buffer.from(keyString, \"utf-8\")\n }\n\n encrypt(plaintext: string): string {\n if (!this.aesKey) throw new Error(\"Encryption key not set\")\n const iv = randomBytes(16)\n const cipher = createCipheriv(\"aes-256-cbc\", this.aesKey, iv)\n const encrypted = Buffer.concat([cipher.update(plaintext, \"utf-8\"), cipher.final()])\n const result = Buffer.concat([iv, encrypted])\n return result.toString(\"base64\")\n }\n\n decrypt(data: string): string {\n if (!this.aesKey) throw new Error(\"Encryption key not set\")\n const buf = Buffer.from(data, \"base64\")\n const iv = buf.subarray(0, 16)\n const ciphertext = buf.subarray(16)\n const decipher = createDecipheriv(\"aes-256-cbc\", this.aesKey, iv)\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString(\"utf-8\")\n }\n\n encode(data: Record<string, unknown>): string {\n return this.encrypted ? this.encrypt(JSON.stringify(data)) : JSON.stringify(data)\n }\n\n decode(data: unknown): Record<string, unknown> {\n if (this.encrypted && typeof data === \"string\") {\n return JSON.parse(this.decrypt(data)) as Record<string, unknown>\n }\n return typeof data === \"string\" ? JSON.parse(data) as Record<string, unknown> : data as Record<string, unknown>\n }\n}\n\nfunction performHandshake(socket: Socket, encryptor: Encryptor): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(\"Handshake timed out\"))\n }, 10_000)\n\n socket.once(\"handshake\", (encryptedKey: string, serverPubKeyB64: string) => {\n clearTimeout(timeout)\n const raw = encryptor.acquireKey(encryptedKey, serverPubKeyB64)\n if (!raw) {\n reject(new Error(\"Failed to decrypt handshake key\"))\n return\n }\n\n const parsed = JSON.parse(raw) as { key: string; time?: number }\n if (parsed.time && typeof parsed.time === \"number\" && Math.abs(Date.now() - parsed.time) > 300_000) {\n reject(new Error(\"Server time desync\"))\n return\n }\n\n encryptor.setKey(parsed.key)\n resolve()\n })\n\n socket.emit(\"handshake\", encryptor.publicKey)\n })\n}\n\n/**\n * Wraps a NewCP socket to decrypt incoming messages into the\n * `{ action, args }` envelope that the Client class expects.\n */\nfunction wrapSocket(raw: Socket, encryptor: Encryptor): Socket {\n const original = raw.on.bind(raw)\n\n raw.on = function (event: string, listener: (...args: unknown[]) => void) {\n if (event === \"message\") {\n return original(event, (msg: unknown) => {\n try {\n const decoded = encryptor.decode(msg)\n listener({ action: decoded.action, args: decoded.args ?? {} })\n } catch {\n // Skip malformed messages\n }\n })\n }\n return original(event, listener)\n } as typeof raw.on\n\n return raw\n}\n\nexport class NewcpAdapter extends BaseAdapter {\n readonly id = \"NewCP\"\n private encryptor = new Encryptor()\n private worlds: CrumbsWorlds | null = null\n\n async login(options: LoginOptions | TokenLoginOptions): Promise<LoginResult> {\n if (!this.worlds) {\n await this.loadWorlds()\n }\n\n const loginWorld = Object.values(this.worlds!).find(w => w.login)\n if (!loginWorld) throw new Error(\"Login world not found in crumbs\")\n\n const loginSocket = this.createSocket(loginWorld.host, loginWorld.path)\n this.encryptor = new Encryptor()\n\n const result = await new Promise<LoginResult>((resolve, reject) => {\n const timeout = setTimeout(() => {\n loginSocket.disconnect()\n reject(new Error(\"Login timed out\"))\n }, 15_000)\n\n loginSocket.on(\"connect\", async () => {\n try {\n await performHandshake(loginSocket, this.encryptor)\n\n const args = \"token\" in options\n ? { username: options.username, token: options.token }\n : { username: options.username, password: options.password }\n\n const encrypted = this.encryptor.encode({ action: \"login\", args })\n loginSocket.emit(\"message\", encrypted)\n } catch (err) {\n clearTimeout(timeout)\n loginSocket.disconnect()\n reject(err)\n }\n })\n\n loginSocket.on(\"message\", (msg: unknown) => {\n try {\n const decoded = this.encryptor.decode(msg)\n if (decoded.action !== \"login\") return\n\n clearTimeout(timeout)\n loginSocket.disconnect()\n\n const response = decoded.args as unknown as LoginResponse\n\n if (!response.success) {\n reject(new Error(\"Login failed\"))\n return\n }\n\n const servers: ServerInfo[] = Object.entries(response.populations ?? {}).map(\n ([name, population]) => ({ name, population }),\n )\n\n resolve({\n servers,\n key: response.key,\n username: response.username,\n moderator: response.moderator ?? false,\n buddyWorlds: response.buddyWorlds ?? [],\n })\n } catch (err) {\n clearTimeout(timeout)\n loginSocket.disconnect()\n reject(err)\n }\n })\n\n loginSocket.on(\"connect_error\", (err: Error) => {\n clearTimeout(timeout)\n loginSocket.disconnect()\n reject(new Error(`Login connection failed: ${err.message}`))\n })\n })\n\n return result\n }\n\n async connect(serverName: string, loginResult: LoginResult, options?: ConnectOptions): Promise<Socket> {\n if (!this.worlds) {\n await this.loadWorlds()\n }\n\n const worldConfig = this.worlds![serverName]\n if (!worldConfig) throw new Error(`World config not found for: ${serverName}`)\n\n this.encryptor = new Encryptor()\n const gameSocket = this.createSocket(worldConfig.host, worldConfig.path)\n this.socket = gameSocket\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n gameSocket.disconnect()\n reject(new Error(\"Game connection timed out\"))\n }, 15_000)\n\n gameSocket.on(\"connect\", async () => {\n try {\n await performHandshake(gameSocket, this.encryptor)\n\n const encrypted = this.encryptor.encode({\n action: \"game_auth\",\n args: {\n username: loginResult.username,\n key: loginResult.key,\n createToken: false,\n },\n })\n gameSocket.emit(\"message\", encrypted)\n } catch (err) {\n clearTimeout(timeout)\n gameSocket.disconnect()\n reject(err)\n }\n })\n\n gameSocket.on(\"message\", (msg: unknown) => {\n try {\n const decoded = this.encryptor.decode(msg)\n\n switch (decoded.action) {\n case \"wait_queue_update\": {\n options?.onQueueUpdate?.(decoded.args as unknown as QueueUpdate)\n break\n }\n case \"game_auth\": {\n const response = decoded.args as unknown as GameAuthResponse\n if (!response.success) {\n clearTimeout(timeout)\n gameSocket.disconnect()\n reject(new Error(\"Game auth failed\"))\n return\n }\n\n const joinEncrypted = this.encryptor.encode({ action: \"join_server\", args: {} })\n gameSocket.emit(\"message\", joinEncrypted)\n clearTimeout(timeout)\n resolve()\n break\n }\n }\n } catch {\n // Ignore decode errors during auth phase\n }\n })\n\n gameSocket.on(\"connect_error\", (err: Error) => {\n clearTimeout(timeout)\n gameSocket.disconnect()\n reject(new Error(`Game connection failed: ${err.message}`))\n })\n })\n\n return wrapSocket(gameSocket, this.encryptor)\n }\n\n send(action: string, args: Record<string, unknown>): void {\n if (!this.socket) throw new Error(\"Not connected\")\n const encrypted = this.encryptor.encode({ action, args })\n this.socket.emit(\"message\", encrypted)\n }\n\n disconnect(): void {\n this.socket?.disconnect()\n this.socket = null\n }\n\n private createSocket(host: string, path: string): Socket {\n return io(host, {\n path,\n transports: [\"polling\", \"websocket\"],\n reconnection: false,\n })\n }\n\n private async loadWorlds(): Promise<void> {\n const resp = await fetch(CRUMBS_URL)\n if (!resp.ok) throw new Error(`Failed to fetch crumbs: ${resp.status}`)\n const crumbs = await resp.json() as { worlds: CrumbsWorlds }\n this.worlds = crumbs.worlds\n }\n}\n","import type { BaseAdapter } from \"./base-adapter.js\"\nimport { CpjourneyAdapter } from \"./cpjourney-adapter.js\"\nimport { CplegacyAdapter } from \"./cplegacy-adapter.js\"\nimport { NewcpAdapter } from \"./newcp-adapter.js\"\n\nconst ADAPTERS = {\n CPJourney: CpjourneyAdapter,\n CPLegacy: CplegacyAdapter,\n NewCP: NewcpAdapter,\n} as const\n\nexport type AdapterName = keyof typeof ADAPTERS\n\nexport function createAdapter(name: AdapterName): BaseAdapter {\n return new ADAPTERS[name]()\n}\n"],"mappings":"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","names":["EventEmitter","io","msgpackParser","BaseAdapter","message","emote","safe","x","y","frame","set","room","item","id","type","userId","cardId","igloo","coins","stamp","BASE_URL","DEFAULT_SECRET","CpjourneyAdapter","BaseAdapter","options","loginSocket","resolve","reject","timeout","secret","args","msg","response","servers","name","population","err","serverName","loginResult","gameSocket","authSent","action","path","io","msgpackParser","io","msgpackParser","LOGIN_URL","TOKEN_LOGIN_URL","wrapSocket","raw","original","event","listener","action","args","CplegacyAdapter","BaseAdapter","options","url","body","data","name","population","serverName","loginResult","wsUrl","rawSocket","io","msgpackParser","resolve","reject","timeout","err","createCipheriv","createDecipheriv","randomBytes","io","nacl","CRUMBS_URL","Encryptor","nacl","encryptedB64","serverPubKeyB64","data","serverPubKey","nonce","ciphertext","plaintext","keyString","iv","randomBytes","cipher","createCipheriv","encrypted","buf","decipher","createDecipheriv","performHandshake","socket","encryptor","resolve","reject","timeout","encryptedKey","raw","parsed","wrapSocket","original","event","listener","msg","decoded","NewcpAdapter","BaseAdapter","options","loginWorld","w","loginSocket","args","err","response","servers","name","population","serverName","loginResult","worldConfig","gameSocket","joinEncrypted","action","host","path","io","resp","crumbs","ADAPTERS","CpjourneyAdapter","CplegacyAdapter","NewcpAdapter","createAdapter","name","isMessagePayload","msg","Client","EventEmitter","server","options","createAdapter","serverName","connectOptions","update","socket","resolve","reject","timeout","playerLoaded","roomJoined","checkReady","onMessage","onDisconnect","event","listener","args","message","emote","safe","x","y","frame","set","room","item","id","type","userId","cardId","igloo","coins","stamp","ms","action","user","users","slot","reason","error","eventName"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaunlwm/pickle.ts",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Club Penguin Private Server client library",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,8 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "socket.io-client": "^4.8.1",
23
- "socket.io-msgpack-parser": "^3.0.2"
23
+ "socket.io-msgpack-parser": "^3.0.2",
24
+ "tweetnacl": "^1.0.3"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@types/node": "^22.0.0",