├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── .npmignore ├── .openapi-generator-ignore ├── .openapi-generator ├── FILES └── VERSION ├── LICENSE ├── README.md ├── api.ts ├── base.ts ├── common.ts ├── configuration.ts ├── cookies_load.js ├── cookies_store.js ├── example.js ├── generate.sh ├── index.ts ├── openapitools.json ├── package-lock.json ├── package.json └── tsconfig.json /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | repository_dispatch: 3 | types: [spec_release] 4 | #on: push 5 | 6 | name: Generate VRChat API SDK 7 | 8 | jobs: 9 | generate: 10 | runs-on: ubuntu-latest 11 | name: Generate VRChat API SDK 12 | steps: 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: 16 16 | - uses: actions/checkout@v2 17 | - name: 'Cache node_modules' 18 | uses: actions/cache@v4 19 | with: 20 | path: node_modules 21 | key: ${{ runner.os }}-node-v16-${{ hashFiles('**/generate.sh') }} 22 | restore-keys: | 23 | ${{ runner.os }}-node-v16 24 | - name: Install OpenAPI Generator CLI 25 | run: npm install @openapitools/openapi-generator-cli 26 | - name: Set OpenAPI Generator version 27 | run: ./node_modules/\@openapitools/openapi-generator-cli/main.js version-manager set 6.3.1 28 | - name: Generate SDK Client 29 | run: bash ./generate.sh 30 | - name: Check version number 31 | run: | 32 | echo "spec_version=$(grep "version" ./package.json | cut -d "\"" -f 4)" >> $GITHUB_ENV 33 | - name: Print version number 34 | run: echo ${{ env.spec_version }} 35 | - name: Deploy SDK back into main branch 36 | uses: JamesIves/github-pages-deploy-action@v4 37 | with: 38 | branch: main 39 | folder: . 40 | commit-message: "Upgrade Node SDK to spec ${{ env.spec_version }}" 41 | - name: Upload to NPM 42 | uses: JS-DevTools/npm-publish@v1 43 | with: 44 | token: ${{ secrets.NPM_TOKEN }} 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # NPM build output directory 36 | dist -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm -------------------------------------------------------------------------------- /.openapi-generator-ignore: -------------------------------------------------------------------------------- 1 | # OpenAPI Generator Ignore 2 | # Generated by openapi-generator https://github.com/openapitools/openapi-generator 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | 25 | 26 | # VRChatAPI: Do not modify .gitignore to avoid comitting "dist" 27 | .gitignore 28 | README.md 29 | git_push.sh -------------------------------------------------------------------------------- /.openapi-generator/FILES: -------------------------------------------------------------------------------- 1 | .npmignore 2 | api.ts 3 | base.ts 4 | common.ts 5 | configuration.ts 6 | index.ts 7 | package.json 8 | tsconfig.json 9 | -------------------------------------------------------------------------------- /.openapi-generator/VERSION: -------------------------------------------------------------------------------- 1 | 6.2.1 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Owners of GitHub organisation "vrchatapi" and individual contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/vrchatapi/vrchatapi.github.io/blob/main/static/assets/img/lang/lang_javascript_banner_1500x300.png?raw=true) 2 | 3 | # VRChat API Library for JavaScript/TypeScript 4 | 5 | A JavaScript/TypeScript/NodeJS client to interact with the unofficial VRChat API. Supports all REST calls specified in the [API specification](https://github.com/vrchatapi/specification). 6 | 7 | ## Disclaimer 8 | 9 | This is the official response of the VRChat Team (from Tupper more specifically) on the usage of the VRChat API. 10 | 11 | > Use of the API using applications other than the approved methods (website, VRChat application) are not officially supported. You may use the API for your own application, but keep these guidelines in mind: 12 | > * We do not provide documentation or support for the API. 13 | > * Do not make queries to the API more than once per 60 seconds. 14 | > * Abuse of the API may result in account termination. 15 | > * Access to API endpoints may break at any given time, with no warning. 16 | 17 | As stated, this documentation was not created with the help of the official VRChat team. Therefore this documentation is not an official documentation of the VRChat API and may not be always up to date with the latest versions. If you find that a page or endpoint is not longer valid please create an issue and tell us so we can fix it. 18 | 19 | ## Getting Started 20 | 21 | First add the package to to your project: 22 | ```bash 23 | npm install vrchat 24 | ``` 25 | 26 | Below is an example on how to login to the API and fetch your own user information. 27 | 28 | ```javascript 29 | // Step 1. We begin with creating a Configuration, which contains the username and password for authentication, as well as an options dictionary, which contains the user agent header. 30 | const vrchat = require("vrchat"); 31 | 32 | const configuration = new vrchat.Configuration({ 33 | username: "username", 34 | password: "password" 35 | }); 36 | 37 | const options = { headers: { "User-Agent": "ExampleProgram/0.0.1 my@email.com"}}; 38 | 39 | // Step 2. VRChat consists of several API's (WorldsApi, UsersApi, FilesApi, NotificationsApi, FriendsApi, etc...) 40 | // Here we instantiate the Authentication API which is required for logging in. 41 | const AuthenticationApi = new vrchat.AuthenticationApi(configuration); 42 | 43 | // Step 3. Calling getCurrentUser on Authentication API logs you in if the user isn't already logged in. 44 | AuthenticationApi.getCurrentUser(options).then(async resp => { 45 | var currentUser = resp.data; 46 | 47 | // Step 3.5. Calling email verify2fa if the account has 2FA disabled 48 | if (currentUser["requiresTwoFactorAuth"] && currentUser["requiresTwoFactorAuth"][0] === "emailOtp") { 49 | await AuthenticationApi.verify2FAEmailCode({ code: "123456" }, options) 50 | currentUser = (await AuthenticationApi.getCurrentUser(options)).data; 51 | } 52 | 53 | // Step 3.5. Calling verify2fa if the account has 2FA enabled 54 | if (currentUser["requiresTwoFactorAuth"] && currentUser["requiresTwoFactorAuth"][0] === "totp") { 55 | await AuthenticationApi.verify2FA({ code: "123456" }, options) 56 | currentUser = (await AuthenticationApi.getCurrentUser(options)).data; 57 | } 58 | 59 | console.log(`Logged in as: ${currentUser.displayName}`); 60 | }); 61 | ``` 62 | 63 | See [example.js](https://github.com/vrchatapi/vrchatapi-javascript/blob/master/example.js) for more example usage on getting started. 64 | 65 | ## Contributing 66 | 67 | Contributions are welcome, but do not add features that should be handled by the OpenAPI specification. 68 | 69 | Join the [Discord server](https://discord.gg/Ge2APMhPfD) to get in touch with us. 70 | -------------------------------------------------------------------------------- /base.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | /** 4 | * VRChat API Documentation 5 | * 6 | * The version of the OpenAPI document: 1.19.4 7 | * Contact: vrchatapi.lpv0t@aries.fyi 8 | * 9 | * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). 10 | * https://openapi-generator.tech 11 | * Do not edit the class manually. 12 | */ 13 | 14 | 15 | import { Configuration } from "./configuration"; 16 | // Some imports not used depending on template conditions 17 | // @ts-ignore 18 | import globalAxios, { AxiosPromise, AxiosInstance, AxiosRequestConfig } from 'axios'; 19 | 20 | export const BASE_PATH = "https://api.vrchat.cloud/api/1".replace(/\/+$/, ""); 21 | 22 | /** 23 | * 24 | * @export 25 | */ 26 | export const COLLECTION_FORMATS = { 27 | csv: ",", 28 | ssv: " ", 29 | tsv: "\t", 30 | pipes: "|", 31 | }; 32 | 33 | /** 34 | * 35 | * @export 36 | * @interface RequestArgs 37 | */ 38 | export interface RequestArgs { 39 | url: string; 40 | options: AxiosRequestConfig; 41 | } 42 | 43 | /** 44 | * 45 | * @export 46 | * @class BaseAPI 47 | */ 48 | export class BaseAPI { 49 | protected configuration: Configuration | undefined; 50 | 51 | constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { 52 | if (configuration) { 53 | this.configuration = configuration; 54 | this.basePath = configuration.basePath || this.basePath; 55 | } 56 | } 57 | }; 58 | 59 | /** 60 | * 61 | * @export 62 | * @class RequiredError 63 | * @extends {Error} 64 | */ 65 | export class RequiredError extends Error { 66 | name: "RequiredError" = "RequiredError"; 67 | constructor(public field: string, msg?: string) { 68 | super(msg); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /common.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | /** 4 | * VRChat API Documentation 5 | * 6 | * The version of the OpenAPI document: 1.19.4 7 | * Contact: vrchatapi.lpv0t@aries.fyi 8 | * 9 | * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). 10 | * https://openapi-generator.tech 11 | * Do not edit the class manually. 12 | */ 13 | 14 | 15 | import { Configuration } from "./configuration"; 16 | import { RequiredError, RequestArgs } from "./base"; 17 | import { AxiosInstance, AxiosResponse } from 'axios'; 18 | 19 | /** 20 | * 21 | * @export 22 | */ 23 | export const DUMMY_BASE_URL = 'https://example.com' 24 | 25 | /** 26 | * 27 | * @throws {RequiredError} 28 | * @export 29 | */ 30 | export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { 31 | if (paramValue === null || paramValue === undefined) { 32 | throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); 33 | } 34 | } 35 | 36 | /** 37 | * 38 | * @export 39 | */ 40 | export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { 41 | if (configuration && configuration.apiKey) { 42 | const localVarApiKeyValue = typeof configuration.apiKey === 'function' 43 | ? await configuration.apiKey(keyParamName) 44 | : await configuration.apiKey; 45 | object[keyParamName] = localVarApiKeyValue; 46 | } 47 | } 48 | 49 | /** 50 | * 51 | * @export 52 | */ 53 | export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { 54 | if (configuration && (configuration.username || configuration.password)) { 55 | object["auth"] = { username: configuration.username, password: configuration.password }; 56 | } 57 | } 58 | 59 | /** 60 | * 61 | * @export 62 | */ 63 | export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { 64 | if (configuration && configuration.accessToken) { 65 | const accessToken = typeof configuration.accessToken === 'function' 66 | ? await configuration.accessToken() 67 | : await configuration.accessToken; 68 | object["Authorization"] = "Bearer " + accessToken; 69 | } 70 | } 71 | 72 | /** 73 | * 74 | * @export 75 | */ 76 | export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { 77 | if (configuration && configuration.accessToken) { 78 | const localVarAccessTokenValue = typeof configuration.accessToken === 'function' 79 | ? await configuration.accessToken(name, scopes) 80 | : await configuration.accessToken; 81 | object["Authorization"] = "Bearer " + localVarAccessTokenValue; 82 | } 83 | } 84 | 85 | function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void { 86 | if (typeof parameter === "object") { 87 | if (Array.isArray(parameter)) { 88 | (parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key)); 89 | } 90 | else { 91 | Object.keys(parameter).forEach(currentKey => 92 | setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`) 93 | ); 94 | } 95 | } 96 | else { 97 | if (urlSearchParams.has(key)) { 98 | urlSearchParams.append(key, parameter); 99 | } 100 | else { 101 | urlSearchParams.set(key, parameter); 102 | } 103 | } 104 | } 105 | 106 | /** 107 | * 108 | * @export 109 | */ 110 | export const setSearchParams = function (url: URL, ...objects: any[]) { 111 | const searchParams = new URLSearchParams(url.search); 112 | setFlattenedQueryParams(searchParams, objects); 113 | url.search = searchParams.toString(); 114 | } 115 | 116 | /** 117 | * 118 | * @export 119 | */ 120 | export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { 121 | const nonString = typeof value !== 'string'; 122 | const needsSerialization = nonString && configuration && configuration.isJsonMime 123 | ? configuration.isJsonMime(requestOptions.headers['Content-Type']) 124 | : nonString; 125 | return needsSerialization 126 | ? JSON.stringify(value !== undefined ? value : {}) 127 | : (value || ""); 128 | } 129 | 130 | /** 131 | * 132 | * @export 133 | */ 134 | export const toPathString = function (url: URL) { 135 | return url.pathname + url.search + url.hash 136 | } 137 | 138 | /** 139 | * 140 | * @export 141 | */ 142 | export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { 143 | return >(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { 144 | const axiosRequestArgs = {...axiosArgs.options, url: (configuration?.basePath || basePath) + axiosArgs.url}; 145 | return axios.request(axiosRequestArgs); 146 | }; 147 | } 148 | -------------------------------------------------------------------------------- /configuration.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | /** 4 | * VRChat API Documentation 5 | * 6 | * The version of the OpenAPI document: 1.19.4 7 | * Contact: vrchatapi.lpv0t@aries.fyi 8 | * 9 | * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). 10 | * https://openapi-generator.tech 11 | * Do not edit the class manually. 12 | */ 13 | 14 | 15 | export interface ConfigurationParameters { 16 | apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); 17 | username?: string; 18 | password?: string; 19 | accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); 20 | basePath?: string; 21 | baseOptions?: any; 22 | formDataCtor?: new () => any; 23 | } 24 | 25 | export class Configuration { 26 | /** 27 | * parameter for apiKey security 28 | * @param name security name 29 | * @memberof Configuration 30 | */ 31 | apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); 32 | /** 33 | * parameter for basic security 34 | * 35 | * @type {string} 36 | * @memberof Configuration 37 | */ 38 | username?: string; 39 | /** 40 | * parameter for basic security 41 | * 42 | * @type {string} 43 | * @memberof Configuration 44 | */ 45 | password?: string; 46 | /** 47 | * parameter for oauth2 security 48 | * @param name security name 49 | * @param scopes oauth2 scope 50 | * @memberof Configuration 51 | */ 52 | accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); 53 | /** 54 | * override base path 55 | * 56 | * @type {string} 57 | * @memberof Configuration 58 | */ 59 | basePath?: string; 60 | /** 61 | * base options for axios calls 62 | * 63 | * @type {any} 64 | * @memberof Configuration 65 | */ 66 | baseOptions?: any; 67 | /** 68 | * The FormData constructor that will be used to create multipart form data 69 | * requests. You can inject this here so that execution environments that 70 | * do not support the FormData class can still run the generated client. 71 | * 72 | * @type {new () => FormData} 73 | */ 74 | formDataCtor?: new () => any; 75 | 76 | constructor(param: ConfigurationParameters = {}) { 77 | this.apiKey = param.apiKey; 78 | this.username = param.username; 79 | this.password = param.password; 80 | this.accessToken = param.accessToken; 81 | this.basePath = param.basePath; 82 | this.baseOptions = param.baseOptions; 83 | this.formDataCtor = param.formDataCtor; 84 | } 85 | 86 | /** 87 | * Check if the given MIME is a JSON MIME. 88 | * JSON MIME examples: 89 | * application/json 90 | * application/json; charset=UTF8 91 | * APPLICATION/JSON 92 | * application/vnd.company+json 93 | * @param mime - MIME (Multipurpose Internet Mail Extensions) 94 | * @return True if the given MIME is JSON, false otherwise. 95 | */ 96 | public isJsonMime(mime: string): boolean { 97 | const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); 98 | return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /cookies_load.js: -------------------------------------------------------------------------------- 1 | const vrchat = require("vrchat"); 2 | 3 | const readline = require("readline") 4 | 5 | const tough = require("tough-cookie"); 6 | const fs = require("fs"); 7 | 8 | const COOKIE_FILE = "cookies.json"; 9 | let cookieJar = new tough.CookieJar(); 10 | 11 | if (fs.existsSync(COOKIE_FILE)) { 12 | const serializedCookies = fs.readFileSync(COOKIE_FILE, "utf-8"); 13 | cookieJar = tough.CookieJar.deserializeSync(JSON.parse(serializedCookies)); 14 | } 15 | 16 | const configuration = new vrchat.Configuration({ 17 | username: "username", 18 | password: "password", 19 | baseOptions: { 20 | headers: { 21 | "User-Agent": "ExampleProgram/0.0.1 my@email.com", 22 | // Use this instead of jar if you want to hard code cookies 23 | // "Cookie": "auth=[AUTH_COOKIE_HERE]; twoFactorAuth=[TWO_FACTOR_AUTH_COOKIE_HERE]" 24 | }, 25 | jar: cookieJar, 26 | } 27 | }); 28 | 29 | 30 | const authenticationApi = new AuthenticationApi(configuration); 31 | 32 | async function main() { 33 | var currentUser = (await authenticationApi.getCurrentUser()).data 34 | console.log(`Logged in as: ${currentUser.displayName}`); 35 | } 36 | 37 | main(); 38 | -------------------------------------------------------------------------------- /cookies_store.js: -------------------------------------------------------------------------------- 1 | const vrchat = require("vrchat"); 2 | 3 | const readline = require("readline") 4 | 5 | const tough = require("tough-cookie"); 6 | const fs = require("fs"); 7 | 8 | const rl = readline.createInterface({input: process.stdin, output: process.stdout}); 9 | const prompt = (query) => new Promise((resolve) => rl.question(query, resolve)); 10 | 11 | 12 | const COOKIE_FILE = "cookies.json"; 13 | let cookieJar = new tough.CookieJar(); 14 | 15 | const configuration = new vrchat.Configuration({ 16 | username: "username", 17 | password: "password", 18 | baseOptions: { 19 | headers: { "User-Agent": "ExampleProgram/0.0.1 my@email.com"}, 20 | jar: cookieJar, 21 | } 22 | }); 23 | 24 | 25 | const authenticationApi = new AuthenticationApi(configuration); 26 | 27 | async function main() { 28 | var currentUser = (await authenticationApi.getCurrentUser()).data 29 | 30 | if (currentUser["requiresTwoFactorAuth"] && currentUser["requiresTwoFactorAuth"][0] === "emailOtp") { 31 | await authenticationApi.verify2FAEmailCode({ code: await prompt("email Code\n") }) 32 | currentUser = (await authenticationApi.getCurrentUser()).data; 33 | } 34 | if (currentUser["requiresTwoFactorAuth"] && currentUser["requiresTwoFactorAuth"][0] === "totp") { 35 | await authenticationApi.verify2FA({ code: await prompt("2fa Code\n") }) 36 | currentUser = (await authenticationApi.getCurrentUser()).data; 37 | } 38 | 39 | console.log(`Logged in as: ${currentUser.displayName}`); 40 | 41 | const serializedJar = JSON.stringify(cookieJar.serializeSync()); 42 | fs.writeFileSync(COOKIE_FILE, serializedJar); 43 | 44 | const deserializedJar = tough.CookieJar.deserializeSync(serializedJar); 45 | const store = deserializedJar.store.idx["api.vrchat.cloud"]["/"]; 46 | console.log(`auth=${store["auth"]["value"]}`); 47 | console.log(`twoFactorAuth=${store["twoFactorAuth"]["value"]}`); 48 | } 49 | 50 | main(); 51 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | const vrchat = require("vrchat"); 2 | const readline = require("readline") 3 | 4 | const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); 5 | const prompt = (query) => new Promise((resolve) => rl.question(query, resolve)); 6 | 7 | 8 | const configuration = new vrchat.Configuration({ 9 | username: "username", 10 | password: "password", 11 | baseOptions: { 12 | headers: { "User-Agent": "ExampleProgram/0.0.1 my@email.com"} 13 | } 14 | }); 15 | 16 | const authenticationApi = new vrchat.AuthenticationApi(configuration); 17 | const usersApi = new vrchat.UsersApi(configuration); 18 | const systemApi = new vrchat.SystemApi(configuration); 19 | 20 | async function main() { 21 | var currentUser = (await authenticationApi.getCurrentUser()).data; 22 | 23 | if (currentUser["requiresTwoFactorAuth"] && currentUser["requiresTwoFactorAuth"][0] === "emailOtp") { 24 | await authenticationApi.verify2FAEmailCode({ code: await prompt("email Code\n") }) 25 | currentUser = (await authenticationApi.getCurrentUser()).data; 26 | } 27 | if (currentUser["requiresTwoFactorAuth"] && currentUser["requiresTwoFactorAuth"][0] === "totp") { 28 | await authenticationApi.verify2FA({ code: await prompt("2fa Code\n") }) 29 | currentUser = (await authenticationApi.getCurrentUser()).data; 30 | } 31 | 32 | console.log(`Logged in as: ${currentUser.displayName}`); 33 | 34 | const currentOnlineUsers = (await systemApi.getCurrentOnlineUsers()).data; 35 | console.log(`Current Online Users: ${resp.data}`); 36 | 37 | const tupperUser = (await usersApi.getUser("usr_c1644b5b-3ca4-45b4-97c6-a2a0de70d469")).data; 38 | console.log(resp.data.displayName); 39 | } 40 | 41 | main(); 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npm install @openapitools/openapi-generator-cli 4 | 5 | rm *.ts -rf 6 | 7 | ./node_modules/\@openapitools/openapi-generator-cli/main.js generate \ 8 | -g typescript-axios \ 9 | --additional-properties=npmName=vrchat \ 10 | --git-user-id=vrchatapi \ 11 | --git-repo-id=vrchatapi-javascript \ 12 | -o . \ 13 | -i https://raw.githubusercontent.com/vrchatapi/specification/gh-pages/openapi.yaml \ 14 | --http-user-agent="vrchatapi-javascript" 15 | 16 | # Modify package.json 17 | sed -i 's/OpenAPI client for vrchat/🟡🔵 VRChat API Library for JavaScript and TypeScript/g' ./package.json 18 | sed -i 's/Unlicense/MIT/g' ./package.json 19 | 20 | # Enable global cookies 21 | sed -i '/^import { BASE_PATH/a import axiosCookieJarSupport from "axios-cookiejar-support";axiosCookieJarSupport(globalAxios);import { CookieJar } from "tough-cookie";globalAxios.defaults.jar = new CookieJar();globalAxios.defaults.withCredentials = true;' ./api.ts 22 | 23 | sed -i '/"dependencies"/a "@types/tough-cookie": "^4.0.1",' ./package.json 24 | sed -i '/"dependencies"/a "axios-cookiejar-support": "^1.0.1",' ./package.json 25 | sed -i '/"dependencies"/a "tough-cookie": "^4.0.0",' ./package.json 26 | 27 | # Remove messily pasted markdown at top of every file 28 | for i in *.ts; do 29 | sed -i '/VRChat API Banner/d' $i 30 | done 31 | 32 | npm install 33 | npm run build -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | /** 4 | * VRChat API Documentation 5 | * 6 | * The version of the OpenAPI document: 1.19.4 7 | * Contact: vrchatapi.lpv0t@aries.fyi 8 | * 9 | * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). 10 | * https://openapi-generator.tech 11 | * Do not edit the class manually. 12 | */ 13 | 14 | 15 | export * from "./api"; 16 | export * from "./configuration"; 17 | 18 | -------------------------------------------------------------------------------- /openapitools.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", 3 | "spaces": 2, 4 | "generator-cli": { 5 | "version": "6.2.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vrchat", 3 | "version": "1.19.4", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "vrchat", 9 | "version": "1.19.4", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@types/tough-cookie": "^4.0.1", 13 | "axios": "^0.26.1", 14 | "axios-cookiejar-support": "^1.0.1", 15 | "tough-cookie": "^4.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^12.11.5", 19 | "typescript": "^4.0" 20 | } 21 | }, 22 | "node_modules/@types/node": { 23 | "version": "12.20.19", 24 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.19.tgz", 25 | "integrity": "sha512-niAuZrwrjKck4+XhoCw6AAVQBENHftpXw9F4ryk66fTgYaKQ53R4FI7c9vUGGw5vQis1HKBHDR1gcYI/Bq1xvw==", 26 | "dev": true 27 | }, 28 | "node_modules/@types/tough-cookie": { 29 | "version": "4.0.1", 30 | "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", 31 | "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==" 32 | }, 33 | "node_modules/axios": { 34 | "version": "0.26.1", 35 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", 36 | "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", 37 | "dependencies": { 38 | "follow-redirects": "^1.14.8" 39 | } 40 | }, 41 | "node_modules/axios-cookiejar-support": { 42 | "version": "1.0.1", 43 | "resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-1.0.1.tgz", 44 | "integrity": "sha512-IZJxnAJ99XxiLqNeMOqrPbfR7fRyIfaoSLdPUf4AMQEGkH8URs0ghJK/xtqBsD+KsSr3pKl4DEQjCn834pHMig==", 45 | "dependencies": { 46 | "is-redirect": "^1.0.0", 47 | "pify": "^5.0.0" 48 | }, 49 | "engines": { 50 | "node": ">= 10.0.0" 51 | }, 52 | "peerDependencies": { 53 | "@types/tough-cookie": ">=2.3.3", 54 | "axios": ">=0.16.2", 55 | "tough-cookie": ">=2.3.3" 56 | } 57 | }, 58 | "node_modules/follow-redirects": { 59 | "version": "1.15.6", 60 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", 61 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", 62 | "funding": [ 63 | { 64 | "type": "individual", 65 | "url": "https://github.com/sponsors/RubenVerborgh" 66 | } 67 | ], 68 | "engines": { 69 | "node": ">=4.0" 70 | }, 71 | "peerDependenciesMeta": { 72 | "debug": { 73 | "optional": true 74 | } 75 | } 76 | }, 77 | "node_modules/is-redirect": { 78 | "version": "1.0.0", 79 | "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", 80 | "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", 81 | "engines": { 82 | "node": ">=0.10.0" 83 | } 84 | }, 85 | "node_modules/pify": { 86 | "version": "5.0.0", 87 | "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", 88 | "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", 89 | "engines": { 90 | "node": ">=10" 91 | }, 92 | "funding": { 93 | "url": "https://github.com/sponsors/sindresorhus" 94 | } 95 | }, 96 | "node_modules/psl": { 97 | "version": "1.8.0", 98 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", 99 | "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" 100 | }, 101 | "node_modules/punycode": { 102 | "version": "2.1.1", 103 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 104 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 105 | "engines": { 106 | "node": ">=6" 107 | } 108 | }, 109 | "node_modules/tough-cookie": { 110 | "version": "4.0.0", 111 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", 112 | "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", 113 | "dependencies": { 114 | "psl": "^1.1.33", 115 | "punycode": "^2.1.1", 116 | "universalify": "^0.1.2" 117 | }, 118 | "engines": { 119 | "node": ">=6" 120 | } 121 | }, 122 | "node_modules/typescript": { 123 | "version": "4.9.3", 124 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", 125 | "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", 126 | "dev": true, 127 | "bin": { 128 | "tsc": "bin/tsc", 129 | "tsserver": "bin/tsserver" 130 | }, 131 | "engines": { 132 | "node": ">=4.2.0" 133 | } 134 | }, 135 | "node_modules/universalify": { 136 | "version": "0.1.2", 137 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 138 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 139 | "engines": { 140 | "node": ">= 4.0.0" 141 | } 142 | } 143 | }, 144 | "dependencies": { 145 | "@types/node": { 146 | "version": "12.20.19", 147 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.19.tgz", 148 | "integrity": "sha512-niAuZrwrjKck4+XhoCw6AAVQBENHftpXw9F4ryk66fTgYaKQ53R4FI7c9vUGGw5vQis1HKBHDR1gcYI/Bq1xvw==", 149 | "dev": true 150 | }, 151 | "@types/tough-cookie": { 152 | "version": "4.0.1", 153 | "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", 154 | "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==" 155 | }, 156 | "axios": { 157 | "version": "0.26.1", 158 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", 159 | "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", 160 | "requires": { 161 | "follow-redirects": "^1.14.8" 162 | } 163 | }, 164 | "axios-cookiejar-support": { 165 | "version": "1.0.1", 166 | "resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-1.0.1.tgz", 167 | "integrity": "sha512-IZJxnAJ99XxiLqNeMOqrPbfR7fRyIfaoSLdPUf4AMQEGkH8URs0ghJK/xtqBsD+KsSr3pKl4DEQjCn834pHMig==", 168 | "requires": { 169 | "is-redirect": "^1.0.0", 170 | "pify": "^5.0.0" 171 | } 172 | }, 173 | "follow-redirects": { 174 | "version": "1.15.6", 175 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", 176 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" 177 | }, 178 | "is-redirect": { 179 | "version": "1.0.0", 180 | "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", 181 | "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" 182 | }, 183 | "pify": { 184 | "version": "5.0.0", 185 | "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", 186 | "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==" 187 | }, 188 | "psl": { 189 | "version": "1.8.0", 190 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", 191 | "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" 192 | }, 193 | "punycode": { 194 | "version": "2.1.1", 195 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 196 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 197 | }, 198 | "tough-cookie": { 199 | "version": "4.0.0", 200 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", 201 | "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", 202 | "requires": { 203 | "psl": "^1.1.33", 204 | "punycode": "^2.1.1", 205 | "universalify": "^0.1.2" 206 | } 207 | }, 208 | "typescript": { 209 | "version": "4.9.3", 210 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", 211 | "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", 212 | "dev": true 213 | }, 214 | "universalify": { 215 | "version": "0.1.2", 216 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 217 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vrchat", 3 | "version": "1.19.4", 4 | "description": "🟡🔵 VRChat API Library for JavaScript and TypeScript", 5 | "author": "OpenAPI-Generator Contributors", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/vrchatapi/vrchatapi-javascript.git" 9 | }, 10 | "keywords": [ 11 | "axios", 12 | "typescript", 13 | "openapi-client", 14 | "openapi-generator", 15 | "vrchat" 16 | ], 17 | "license": "MIT", 18 | "main": "./dist/index.js", 19 | "typings": "./dist/index.d.ts", 20 | "scripts": { 21 | "build": "tsc ", 22 | "prepare": "npm run build" 23 | }, 24 | "dependencies": { 25 | "tough-cookie": "^4.0.0", 26 | "axios-cookiejar-support": "^1.0.1", 27 | "@types/tough-cookie": "^4.0.1", 28 | "axios": "^0.26.1" 29 | }, 30 | "devDependencies": { 31 | "@types/node": "^12.11.5", 32 | "typescript": "^4.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "target": "ES5", 5 | "module": "commonjs", 6 | "noImplicitAny": true, 7 | "outDir": "dist", 8 | "rootDir": ".", 9 | "lib": [ 10 | "es6", 11 | "dom" 12 | ], 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ] 16 | }, 17 | "exclude": [ 18 | "dist", 19 | "node_modules" 20 | ] 21 | } 22 | --------------------------------------------------------------------------------