npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@pkmn/login

v0.2.0

Published

Logic for authenticating with Pokémon Showdown

Downloads

72

Readme

@pkmn/login

Test Status License npm version

Logic for authenticating with Pokémon Showdown.

Installation

$ npm install @pkmn/login

Alternatively, as detailed below, if you are using @pkmn/login in the browser and want a convenient way to get started, simply depend on a transpiled and minified version via unpkg:

<script src="https://unpkg.com/@pkmn/login"></script>

Usage

In order to authenticate with Pokémon Showdown, a client must be able to make HTTP(S) requests to Pokémon Showdown's "login server" and to be able to communicate with its "sim server" via a WebSocket connection. A wide variety of libraries for simplifying these networking tasks exist, and as such, @pkmn/login was designed to be completely agnostic to the client's choice of network layer. @pkmn recommends fetch and ws, but @pkmn/login will work equally well with any native or third-party network library.

@pkmn/login provides helpers for several authentication "actions", though Pokémon Showdown expects a particular login flow and attempting actions in an unexpected order will result in confusing error messages:

Any user of Pokémon Showdown begins as a "guest" user. Pokémon Showdown's client will then attempt an upkeep action during initial load to extend any existing credentials for a registered user. This requires the sid cookie to be sent along with the request to identify which credentials are being prolonged. If there are no credentials to upkeep, the user remains as a guest until a rename is attempted. The rename may be unsuccessful because the name attempted requires authentication, at which point a login action is required. If the password is incorrect during login the server will respond with an obtuse error message about attempting to rename yourself as guest, this is just a 'fun' Pokémon Showdown gotcha. If a name is unregistered you may register the name with a password. Finally, you may logout of a name to terminate a session.

Examples

The following examples demonstrate how to use @pkmn/login with various HTTP APIs (which tend to be less homogenous than WebSocket APIs), but a WebSocket is also required to authenticate with Pokémon Showdown. For example purposes, assume a WebSocket named ws has been set up as below:

import * as WebSocket from 'websocket';
import {Protocol} from '@pkmn/protocol';

const server = 'sim.smogon.com';
const serverport = 8000;
const ws = new WebSocket(`ws://${server}:${serverport}/showdown/websocket`);

ws.on('open', ...);
ws.on('close', ...);
ws.on('error', ...);
ws.on('message', message => {
  for (const {args} of Protocol.parse(message)) {
    switch (args[0]) {
      case 'challstr': {
        const challstr = args[1];
        onChallstr(challstr);
        break;
      }
      case 'updateuser': {
        ...
      }
      ...
    }
  }
  });

To see a complete worked example, please see the login CLI which trivially logs in and out of Pokémon Showdown by leveraging @pkmn/login (though note that the majority of the complexity comes from setup). index.html provides a similar example for the browser.

http/https

Node.js's standard https library is somewhat verbose but perfectly functional for use with @pkmn/login:

import * as https from 'https';

import {Action, Actions} from '@pkmn/login';

function fetch(action: Action) {
  return new Promise((resolve, reject) => {
    let buf = '';
    const req = https.request(action.url, {
      method: action.method,
      headers: action.headers
    }, res => {
      if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`));
      res.on('data', d => {
        buf += d;
      });
      res.on('end', () => resolve(buf));
    });
    req.on('error', reject);
    req.write(action.data);
    req.end();
  });
}

async function onChallstr() {
  const action = Actions.login({username: 'User Name', password: 'password', challstr});
  const cmd = action.onResponse(await fetch(action));
  if (cmd) ws.send(cmd);
}

XMLHttpRequest

Similarly, the legacy XMLHttpRequest API can be used within browsers along with @pkmn/login to authenticate:

<script src="https://unpkg.com/@pkmn/login"></script>
<script>
  ...

  async function onChallstr() {
    const action = pkmn.login.login({username: 'User Name', password: 'password', challstr});
    return new Promise((resolve, reject) => {
      const request = new XMLHttpRequest();
      request.addEventListener('load', () => {
        const cmd = action.onResponse(request.responseText);
        if (cmd) ws.send(cmd);
        resolve();
      });
      request.addEventListener('error', reject);
      for (const header in action.headers) {
        request.setRequestHeader(header, action.headers[header]);
      }
      request.open(action.method, action.url);
      request.send(action.data);
    });
  }
</script>

fetch

fetch is the new browser API for HTTP requests (Node.js includes fetch as of v18):

import fetch from 'node-fetch';

import {Actions} from '@pkmn/login';

async function onChallstr() {
  const action = Actions.login({username: 'User Name', password: 'password', challstr});
  const response = await (await fetch(action.url, {
    method: action.method,
    headers: action.headers,
    body: action.data,
  })).text();
  const cmd = action.onResponse(response);
  if (cmd) ws.send(cmd);
}

axios

axios is a very popular HTTP library which can be configured to work in the browser or on Node.js:

import axios from 'axios';

import {Actions} from '@pkmn/login';

async function onChallstr() {
  const action = Actions.login({username: 'User Name', password: 'password', challstr});
  const response = await axios({
    url: action.url,
    method: action.method,
    headers: action.headers,
    data: action.data,
    responseType: action.responseType,
  });
  const cmd = action.onResponse(response);
  if (cmd) ws.send(cmd);
}

jQuery

jQuery is still commonly used in the browser to provide cleaner APIs:

<script src="https://code.jquery.com/jquery.min.js"></script>
<script src="https://unpkg.com/@pkmn/login"></script>
<script>
  ...

  async function onChallstr() {
    const action = pkmn.login.login({username: 'User Name', password: 'password', challstr});
    $.ajax(action.url, {
      method: action.method,
      headers: action.headers,
      data: action.data,
      success: data => {
        const cmd = action.onResponse(data);
        if (cmd) ws.send(cmd);
      },
      dataType: action.responseType,
    });
  }
</script>

Browser

The recommended way of using @pkmn/login in a web browser is to configure your bundler (Webpack, Rollup, Parcel, etc) to minimize it and package it with the rest of your application. If you do not use a bundler, a convenience index.min.js is included in the package. You simply need to depend on ./node_modules/@pkmn/login/build/index.min.js in a script tag (which is what the unpkg shortcut above is doing), after which pkmn.login will be accessible as a global.

License

This package is distributed under the terms of the MIT License.