From 942804b4110187f73031fc650726fd3da97d128e Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Sun, 5 Nov 2023 15:34:26 -0300 Subject: [PATCH 01/15] add HTTP class. forward Authentication header if 'token' is present. --- src/Client.ts | 11 +++++++---- src/core/HTTP.ts | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 src/core/HTTP.ts diff --git a/src/Client.ts b/src/Client.ts index 098af45..7f06b54 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -1,8 +1,7 @@ -import { post, get } from "httpie"; - import { ServerError } from './errors/ServerError'; import { Room, RoomAvailable } from './Room'; import { SchemaConstructor } from './serializer/SchemaSerializer'; +import { HTTP } from "./core/HTTP"; export type JoinOptions = any; @@ -29,6 +28,8 @@ export interface EndpointSettings { } export class Client { + public http: HTTP; + protected settings: EndpointSettings; constructor(settings: string | EndpointSettings = DEFAULT_ENDPOINT) { @@ -59,6 +60,8 @@ export class Client { } this.settings = settings; } + + this.http = new HTTP(this); } public async joinOrCreate(roomName: string, options: JoinOptions = {}, rootSchema?: SchemaConstructor) { @@ -94,7 +97,7 @@ export class Client { public async getAvailableRooms(roomName: string = ""): Promise[]> { return ( - await get(this.getHttpEndpoint(`${roomName}`), { + await this.http.get(`${roomName}`, { headers: { 'Accept': 'application/json' } @@ -165,7 +168,7 @@ export class Client { reuseRoomInstance?: Room, ) { const response = ( - await post(this.getHttpEndpoint(`${method}/${roomName}`), { + await this.http.post(`${method}/${roomName}`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' diff --git a/src/core/HTTP.ts b/src/core/HTTP.ts new file mode 100644 index 0000000..a836622 --- /dev/null +++ b/src/core/HTTP.ts @@ -0,0 +1,33 @@ +import { Client } from "../Client"; +import { post, get, put, del, Response, Options } from "httpie"; + +export class HTTP { + public token: string; + + constructor(protected client: Client) {} + + public get(path: string, options: Partial = {}): Promise> { + return get(this.client['getHttpEndpoint'](path), options); + } + + public post(path: string, options: Partial = {}): Promise> { + return post(this.client['getHttpEndpoint'](path), options); + } + + public del(path: string, options: Partial = {}): Promise> { + return del(this.client['getHttpEndpoint'](path), options); + } + + public put(path: string, options: Partial = {}): Promise> { + return put(this.client['getHttpEndpoint'](path), options); + } + + protected getOptions(options: Partial) { + if (this.token) { + if (!options.headers) { options.headers = {}; } + options.headers['Authorization'] = `Bearer ${this.token}`; + } + + return options; + } +} From fea0c66db17fd371e66f440db9af4e209a1505a0 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 9 Nov 2023 14:24:49 -0300 Subject: [PATCH 02/15] refactor HTTP module --- package.json | 2 +- src/Client.ts | 16 +++++++++++++++- src/{core => }/HTTP.ts | 13 ++++++++----- 3 files changed, 24 insertions(+), 7 deletions(-) rename src/{core => }/HTTP.ts (77%) diff --git a/package.json b/package.json index a1fd132..280fa6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.14", + "version": "0.15.15-alpha.0", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Client.ts b/src/Client.ts index 7f06b54..903c810 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -1,7 +1,7 @@ import { ServerError } from './errors/ServerError'; import { Room, RoomAvailable } from './Room'; import { SchemaConstructor } from './serializer/SchemaSerializer'; -import { HTTP } from "./core/HTTP"; +import { HTTP } from "./HTTP"; export type JoinOptions = any; @@ -64,6 +64,14 @@ export class Client { this.http = new HTTP(this); } + public set authToken(token: string) { + this.http.authToken = token; + } + + public get authToken(): string { + return this.http.authToken; + } + public async joinOrCreate(roomName: string, options: JoinOptions = {}, rootSchema?: SchemaConstructor) { return await this.createMatchMakeRequest('joinOrCreate', roomName, options, rootSchema); } @@ -196,6 +204,12 @@ export class Client { protected buildEndpoint(room: any, options: any = {}) { const params = []; + // manually append authToken + if (this.http.authToken) { + params.push(`authToken=${this.http.authToken}`); + } + + // append provided options for (const name in options) { if (!options.hasOwnProperty(name)) { continue; diff --git a/src/core/HTTP.ts b/src/HTTP.ts similarity index 77% rename from src/core/HTTP.ts rename to src/HTTP.ts index a836622..5e7d70c 100644 --- a/src/core/HTTP.ts +++ b/src/HTTP.ts @@ -1,8 +1,8 @@ -import { Client } from "../Client"; +import { Client } from "./Client"; import { post, get, put, del, Response, Options } from "httpie"; export class HTTP { - public token: string; + public authToken: string; constructor(protected client: Client) {} @@ -23,9 +23,12 @@ export class HTTP { } protected getOptions(options: Partial) { - if (this.token) { - if (!options.headers) { options.headers = {}; } - options.headers['Authorization'] = `Bearer ${this.token}`; + if (this.authToken) { + if (!options.headers) { + options.headers = {}; + } + + options.headers['Authorization'] = `Bearer ${this.authToken}`; } return options; From 56d7cdc90087448bd8a3e134065290d2e051d0a9 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Mon, 13 Nov 2023 18:33:07 -0300 Subject: [PATCH 03/15] refactor authToken and Auth methods. --- package.json | 2 +- src/Auth.ts | 238 ++++++++++++++------------------------------------ src/Client.ts | 16 +--- src/HTTP.ts | 9 +- 4 files changed, 73 insertions(+), 192 deletions(-) diff --git a/package.json b/package.json index 280fa6c..111c6d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-alpha.0", + "version": "0.15.15-alpha.3", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index 5b2aa29..ac9357c 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -1,206 +1,96 @@ -import * as http from "httpie"; -import { getItem, setItem, removeItem } from "./Storage"; +import { HTTP } from "./HTTP"; -const TOKEN_STORAGE = "colyseus-auth-token"; - -export enum Platform { - ios = "ios", - android = "android", -} - -export interface Device { - id: string, - platform: Platform -} - -export interface IStatus { - status: boolean; +export interface AuthSettings { + path: string; } -export interface IUser { - _id: string; - username: string; - displayName: string; - avatarUrl: string; - - isAnonymous: boolean; - email: string; - - lang: string; - location: string; - timezone: string; - metadata: any; - - devices: Device[]; - - facebookId: string; - twitterId: string; - googleId: string; - gameCenterId: string; - steamId: string; - - friendIds: string[]; - blockedUserIds: string[]; - - createdAt: Date; - updatedAt: Date; +export interface PopupSettings { + prefix: string; + width: number; + height: number; } -export class Auth implements IUser { - _id: string = undefined; - username: string = undefined; - displayName: string = undefined; - avatarUrl: string = undefined; - - isAnonymous: boolean = undefined; - email: string = undefined; - - lang: string = undefined; - location: string = undefined; - timezone: string = undefined; - metadata: any = undefined; - - devices: Device[] = undefined; - - facebookId: string = undefined; - twitterId: string = undefined; - googleId: string = undefined; - gameCenterId: string = undefined; - steamId: string = undefined; - - friendIds: string[] = undefined; - blockedUserIds: string[] = undefined; - - createdAt: Date = undefined; - updatedAt: Date = undefined; - - // auth token - token: string = undefined; +export class Auth { + settings: AuthSettings = { path: "/auth" }; + #_signInWindow = undefined; - protected endpoint: string; - protected keepOnlineInterval: any; + constructor(protected http: HTTP) {} - constructor(endpoint: string) { - this.endpoint = endpoint.replace("ws", "http"); - getItem(TOKEN_STORAGE, (token) => this.token = token); + public set token(token: string) { + this.http.authToken = token; } - get hasToken() { - return !!this.token; + public get token(): string { + return this.http.authToken; } - async login (options: { - accessToken?: string, - deviceId?: string, - platform?: string, - email?: string, - password?: string, - } = {}) { - const queryParams: any = Object.assign({}, options); - - if (this.hasToken) { - queryParams.token = this.token; - } - - const data = await this.request('post', '/auth', queryParams); - - // set & cache token - this.token = data.token; - setItem(TOKEN_STORAGE, this.token); - - for (let attr in data) { - if (this.hasOwnProperty(attr)) { this[attr] = data[attr]; } - } - - this.registerPingService(); - - return this; + public async createUserWithEmailAndPassword(email: string, password: string) { + return (await this.http.post(`${this.settings.path}/register`, { + headers: { 'Content-Type': 'application/json' }, + body: { email, password, }, + })).data; } - async save() { - await this.request('put', '/auth', {}, { - username: this.username, - displayName: this.displayName, - avatarUrl: this.avatarUrl, - lang: this.lang, - location: this.location, - timezone: this.timezone, - }); - - return this; + public async signInWithEmailAndPassword(email: string, password: string) { + return (await this.http.post(`${this.settings.path}/login`, { + headers: { 'Content-Type': 'application/json' }, + body: { email, password, }, + })).data; } - async getFriends() { - return (await this.request('get', '/friends/all')) as IUser[]; + public async signInAnonymously() { + return (await this.http.post(`${this.settings.path}/anonymous`, { + headers: { 'Content-Type': 'application/json' } + })).data; } - async getOnlineFriends() { - return (await this.request('get', '/friends/online')) as IUser[]; - } + public async signInWithOAuth(providerName: string, settings: Partial = {}) { + return new Promise((resolve, reject) => { + const w = settings.width || 480; + const h = settings.height || 768; - async getFriendRequests() { - return (await this.request('get', '/friends/requests')) as IUser[]; - } + // Capitalize first letter of providerName + const title = `Login with ${(providerName[0].toUpperCase() + providerName.substring(1))}`; + const url = this.http['client']['getHttpEndpoint'](`${(settings.prefix || "oauth")}/${providerName}`); - async sendFriendRequest(friendId: string) { - return (await this.request('post', '/friends/requests', { userId: friendId })) as IStatus; - } + const left = (screen.width / 2) - (w / 2); + const top = (screen.height / 2) - (h / 2); - async acceptFriendRequest(friendId: string) { - return (await this.request('put', '/friends/requests', { userId: friendId })) as IStatus; - } + this.#_signInWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left); - async declineFriendRequest(friendId: string) { - return (await this.request('del', '/friends/requests', { userId: friendId })) as IStatus; - } + const onMessage = (event: MessageEvent) => { + // TODO: it is a good idea to check if event.origin can be trusted! + debugger; + // if (event.origin.indexOf(window.location.hostname) === -1) { return; } - async blockUser(friendId: string) { - return (await this.request('post', '/friends/block', { userId: friendId })) as IStatus; - } + console.log("popup, event =>", event); + console.log("popup, event.data =>", event.data); - async unblockUser(friendId: string) { - return (await this.request('put', '/friends/block', { userId: friendId })) as IStatus; - } + // require 'user' and 'token' inside received data. + if (!event.data.user && !event.data.token) { return; } - async request( - method: 'get' | 'post' | 'put' | 'del', - segments: string, - query: {[key: string]: number | string} = {}, - body?: any, - headers: {[key: string]: string} = {} - ) { - headers['Accept'] = 'application/json'; - if (this.hasToken) { headers['Authorization'] = 'Bearer ' + this.token; } - - const queryParams: string[] = []; - for (const name in query) { - queryParams.push(`${name}=${query[name]}`); - } - - const queryString = (queryParams.length > 0) - ? `?${queryParams.join("&")}` - : ''; - - const opts: Partial = { headers }; - if (body) { opts.body = body; } - - return (await http[method](`${this.endpoint}${segments}${queryString}`, opts)).data; - } + clearInterval(rejectionChecker); + this.#_signInWindow.close(); + this.#_signInWindow = undefined; - logout() { - this.token = undefined; - removeItem(TOKEN_STORAGE); - this.unregisterPingService(); - } + window.removeEventListener("message", onMessage); + resolve(event.data); + } - registerPingService(timeout: number = 15000) { - this.unregisterPingService(); + const rejectionChecker = setInterval(() => { + if (!this.#_signInWindow || this.#_signInWindow.closed) { + this.#_signInWindow = undefined; + reject(); + window.removeEventListener("message", onMessage); + } + }, 200); - this.keepOnlineInterval = setInterval(() => this.request('get', '/auth'), timeout); + window.addEventListener("message", onMessage); + }); } - unregisterPingService() { - clearInterval(this.keepOnlineInterval); + public async signOut() { + this.http.authToken = undefined; } } diff --git a/src/Client.ts b/src/Client.ts index 903c810..b746580 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -2,6 +2,7 @@ import { ServerError } from './errors/ServerError'; import { Room, RoomAvailable } from './Room'; import { SchemaConstructor } from './serializer/SchemaSerializer'; import { HTTP } from "./HTTP"; +import { Auth } from './Auth'; export type JoinOptions = any; @@ -29,6 +30,7 @@ export interface EndpointSettings { export class Client { public http: HTTP; + public auth: Auth; protected settings: EndpointSettings; @@ -62,14 +64,7 @@ export class Client { } this.http = new HTTP(this); - } - - public set authToken(token: string) { - this.http.authToken = token; - } - - public get authToken(): string { - return this.http.authToken; + this.auth = new Auth(this.http); } public async joinOrCreate(roomName: string, options: JoinOptions = {}, rootSchema?: SchemaConstructor) { @@ -204,11 +199,6 @@ export class Client { protected buildEndpoint(room: any, options: any = {}) { const params = []; - // manually append authToken - if (this.http.authToken) { - params.push(`authToken=${this.http.authToken}`); - } - // append provided options for (const name in options) { if (!options.hasOwnProperty(name)) { diff --git a/src/HTTP.ts b/src/HTTP.ts index 5e7d70c..d11929e 100644 --- a/src/HTTP.ts +++ b/src/HTTP.ts @@ -7,19 +7,19 @@ export class HTTP { constructor(protected client: Client) {} public get(path: string, options: Partial = {}): Promise> { - return get(this.client['getHttpEndpoint'](path), options); + return get(this.client['getHttpEndpoint'](path), this.getOptions(options)); } public post(path: string, options: Partial = {}): Promise> { - return post(this.client['getHttpEndpoint'](path), options); + return post(this.client['getHttpEndpoint'](path), this.getOptions(options)); } public del(path: string, options: Partial = {}): Promise> { - return del(this.client['getHttpEndpoint'](path), options); + return del(this.client['getHttpEndpoint'](path), this.getOptions(options)); } public put(path: string, options: Partial = {}): Promise> { - return put(this.client['getHttpEndpoint'](path), options); + return put(this.client['getHttpEndpoint'](path), this.getOptions(options)); } protected getOptions(options: Partial) { @@ -29,6 +29,7 @@ export class HTTP { } options.headers['Authorization'] = `Bearer ${this.authToken}`; + options.withCredentials = true; } return options; From dc8f288389c7b0501282d293955774cf708c451d Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 23 Nov 2023 14:34:58 -0300 Subject: [PATCH 04/15] add auth.onChange() callback. --- package.json | 2 +- src/Auth.ts | 37 +++++++++++++++++++++++++++++++++---- src/index.ts | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 111c6d3..e6535a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-alpha.3", + "version": "0.15.15-preview.5", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index ac9357c..aa2e6c5 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -1,4 +1,5 @@ import { HTTP } from "./HTTP"; +import { createNanoEvents } from './core/nanoevents'; export interface AuthSettings { path: string; @@ -10,9 +11,15 @@ export interface PopupSettings { height: number; } +export interface AuthData { + user: any; + token: string; +} + export class Auth { settings: AuthSettings = { path: "/auth" }; #_signInWindow = undefined; + #_events = createNanoEvents(); constructor(protected http: HTTP) {} @@ -24,24 +31,42 @@ export class Auth { return this.http.authToken; } - public async createUserWithEmailAndPassword(email: string, password: string) { - return (await this.http.post(`${this.settings.path}/register`, { + public onChange(callback: (response: AuthData) => void) { + return this.#_events.on("change", callback); + } + + public async registerWithEmailAndPassword(email: string, password: string) { + const data = (await this.http.post(`${this.settings.path}/register`, { headers: { 'Content-Type': 'application/json' }, body: { email, password, }, })).data; + + // emit change event + this.#_events.emit("change", data); + + return data; } public async signInWithEmailAndPassword(email: string, password: string) { - return (await this.http.post(`${this.settings.path}/login`, { + const data = (await this.http.post(`${this.settings.path}/login`, { headers: { 'Content-Type': 'application/json' }, body: { email, password, }, })).data; + + // emit change event + this.#_events.emit("change", data); + + return data; } public async signInAnonymously() { - return (await this.http.post(`${this.settings.path}/anonymous`, { + const data = (await this.http.post(`${this.settings.path}/anonymous`, { headers: { 'Content-Type': 'application/json' } })).data; + + this.#_events.emit("change", data); + + return data; } public async signInWithOAuth(providerName: string, settings: Partial = {}) { @@ -75,6 +100,9 @@ export class Auth { window.removeEventListener("message", onMessage); resolve(event.data); + + // emit change event + this.#_events.emit("change", event.data); } const rejectionChecker = setInterval(() => { @@ -91,6 +119,7 @@ export class Auth { public async signOut() { this.http.authToken = undefined; + this.#_events.emit("change", { user: null, token: null }); } } diff --git a/src/index.ts b/src/index.ts index 78d82d3..531f88b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ import './legacy'; export { Client, JoinOptions } from './Client'; export { Protocol, ErrorCode } from './Protocol'; export { Room, RoomAvailable } from './Room'; -export { Auth, Platform, Device } from "./Auth"; +export { Auth, type AuthSettings, type PopupSettings } from "./Auth"; /* * Serializers From d4adf6f44cf911ed4b2bfb62ac5a443310842383 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 23 Nov 2023 15:00:09 -0300 Subject: [PATCH 05/15] refactor getHttpEndpoint() --- package.json | 2 +- src/Auth.ts | 2 +- src/Client.ts | 13 +++++++++---- test/client_test.ts | 12 ++++++------ 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index e6535a0..d1f995c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.5", + "version": "0.15.15-preview.6", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index aa2e6c5..59cfd6a 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -69,7 +69,7 @@ export class Auth { return data; } - public async signInWithOAuth(providerName: string, settings: Partial = {}) { + public async oauth(providerName: string, settings: Partial = {}) { return new Promise((resolve, reject) => { const w = settings.width || 480; const h = settings.height || 768; diff --git a/src/Client.ts b/src/Client.ts index b746580..0e344a9 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -45,7 +45,7 @@ export class Client { this.settings = { hostname: url.hostname, - pathname: url.pathname !== "/" ? url.pathname : "", + pathname: url.pathname, port, secure }; @@ -63,6 +63,11 @@ export class Client { this.settings = settings; } + // make sure pathname does not end with "/" + if (this.settings.pathname.endsWith("/")) { + this.settings.pathname = this.settings.pathname.slice(0, -1); + } + this.http = new HTTP(this); this.auth = new Auth(this.http); } @@ -100,7 +105,7 @@ export class Client { public async getAvailableRooms(roomName: string = ""): Promise[]> { return ( - await this.http.get(`${roomName}`, { + await this.http.get(`matchmake/${roomName}`, { headers: { 'Accept': 'application/json' } @@ -171,7 +176,7 @@ export class Client { reuseRoomInstance?: Room, ) { const response = ( - await this.http.post(`${method}/${roomName}`, { + await this.http.post(`matchmake/${method}/${roomName}`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' @@ -222,7 +227,7 @@ export class Client { } protected getHttpEndpoint(segments: string = '') { - return `${(this.settings.secure) ? "https" : "http"}://${this.settings.hostname}${this.getEndpointPort()}${this.settings.pathname}/matchmake/${segments}`; + return `${(this.settings.secure) ? "https" : "http"}://${this.settings.hostname}${this.getEndpointPort()}${this.settings.pathname}/${segments}`; } protected getEndpointPort() { diff --git a/test/client_test.ts b/test/client_test.ts index a1dc7f5..b877276 100644 --- a/test/client_test.ts +++ b/test/client_test.ts @@ -18,25 +18,25 @@ describe("Client", function () { const settingsByUrl = { 'ws://localhost:2567': { settings: { hostname: "localhost", port: 2567, secure: false, }, - httpEndpoint: "http://localhost:2567", + httpEndpoint: "http://localhost:2567/", wsEndpoint: "ws://localhost:2567/processId/roomId?", wsEndpointPublicAddress: "ws://node-1.colyseus.cloud/processId/roomId?" }, 'wss://localhost:2567': { settings: { hostname: "localhost", port: 2567, secure: true, }, - httpEndpoint: "https://localhost:2567", + httpEndpoint: "https://localhost:2567/", wsEndpoint: "wss://localhost:2567/processId/roomId?", wsEndpointPublicAddress: "wss://node-1.colyseus.cloud/processId/roomId?" }, 'http://localhost': { settings: { hostname: "localhost", port: 80, secure: false, }, - httpEndpoint: "http://localhost", + httpEndpoint: "http://localhost/", wsEndpoint: "ws://localhost/processId/roomId?", wsEndpointPublicAddress: "ws://node-1.colyseus.cloud/processId/roomId?" }, 'https://localhost/custom/path': { settings: { hostname: "localhost", port: 443, secure: true, pathname: "/custom/path" }, - httpEndpoint: "https://localhost/custom/path", + httpEndpoint: "https://localhost/custom/path/", wsEndpoint: "wss://localhost/custom/path/processId/roomId?", wsEndpointPublicAddress: "wss://node-1.colyseus.cloud/processId/roomId?" }, @@ -49,7 +49,7 @@ describe("Client", function () { assert.strictEqual(expected.settings.hostname, settings.hostname); assert.strictEqual(expected.settings.port, settings.port); assert.strictEqual(expected.settings.secure, settings.secure); - assert.strictEqual(expected.httpEndpoint + "/matchmake/", client['getHttpEndpoint']()); + assert.strictEqual(expected.httpEndpoint, client['getHttpEndpoint']()); assert.strictEqual(expected.wsEndpoint, client['buildEndpoint'](room)); assert.strictEqual(expected.wsEndpointPublicAddress, client['buildEndpoint'](roomWithPublicAddress)); @@ -57,7 +57,7 @@ describe("Client", function () { assert.strictEqual(expected.settings.hostname, clientWithSettings['settings'].hostname); assert.strictEqual(expected.settings.port, clientWithSettings['settings'].port); assert.strictEqual(expected.settings.secure, clientWithSettings['settings'].secure); - assert.strictEqual(expected.httpEndpoint + "/matchmake/", clientWithSettings['getHttpEndpoint']()); + assert.strictEqual(expected.httpEndpoint, clientWithSettings['getHttpEndpoint']()); assert.strictEqual(expected.wsEndpoint, clientWithSettings['buildEndpoint'](room)); assert.strictEqual(expected.wsEndpointPublicAddress, clientWithSettings['buildEndpoint'](roomWithPublicAddress)); } From 566400153be776d8dafa7fc6e08ea639ab85f0b2 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Thu, 23 Nov 2023 17:39:12 -0300 Subject: [PATCH 06/15] fetch token on Auth's constructor. store token when emitting change. --- package.json | 2 +- src/Auth.ts | 34 ++++++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index d1f995c..81337c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.6", + "version": "0.15.15-preview.7", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index 59cfd6a..b2cb446 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -1,8 +1,10 @@ import { HTTP } from "./HTTP"; +import { getItem, setItem } from "./Storage"; import { createNanoEvents } from './core/nanoevents'; export interface AuthSettings { path: string; + key: string; } export interface PopupSettings { @@ -17,11 +19,17 @@ export interface AuthData { } export class Auth { - settings: AuthSettings = { path: "/auth" }; + settings: AuthSettings = { + path: "/auth", + key: "colyseus-auth-token", + }; + #_signInWindow = undefined; #_events = createNanoEvents(); - constructor(protected http: HTTP) {} + constructor(protected http: HTTP) { + getItem(this.settings.key, (token) => this.token = token); + } public set token(token: string) { this.http.authToken = token; @@ -41,8 +49,7 @@ export class Auth { body: { email, password, }, })).data; - // emit change event - this.#_events.emit("change", data); + this.emitChange(data); return data; } @@ -53,8 +60,7 @@ export class Auth { body: { email, password, }, })).data; - // emit change event - this.#_events.emit("change", data); + this.emitChange(data); return data; } @@ -64,7 +70,7 @@ export class Auth { headers: { 'Content-Type': 'application/json' } })).data; - this.#_events.emit("change", data); + this.emitChange(data); return data; } @@ -101,8 +107,7 @@ export class Auth { window.removeEventListener("message", onMessage); resolve(event.data); - // emit change event - this.#_events.emit("change", event.data); + this.emitChange(event.data); } const rejectionChecker = setInterval(() => { @@ -119,7 +124,16 @@ export class Auth { public async signOut() { this.http.authToken = undefined; - this.#_events.emit("change", { user: null, token: null }); + this.emitChange({ user: null, token: null }); + } + + private emitChange(authData: AuthData) { + this.token = authData.token; + + // store key in localStorage + setItem(this.settings.key, authData.token); + + this.#_events.emit("change", authData); } } From 22fe16f0636a27cf439e71db89e9722e56dc4f99 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 24 Nov 2023 11:18:02 -0300 Subject: [PATCH 07/15] fix endpoint generation when segments start with / --- package.json | 2 +- src/Auth.ts | 20 +++++++++++++++++--- src/Client.ts | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 81337c1..19f12ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.7", + "version": "0.15.15-preview.9", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index b2cb446..abab77d 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -24,6 +24,8 @@ export class Auth { key: "colyseus-auth-token", }; + #_initialized = false; + #_initializationPromise: Promise; #_signInWindow = undefined; #_events = createNanoEvents(); @@ -40,7 +42,20 @@ export class Auth { } public onChange(callback: (response: AuthData) => void) { - return this.#_events.on("change", callback); + const unbindChange = this.#_events.on("change", callback); + if (!this.#_initialized) { + this.#_initializationPromise = new Promise((resolve, reject) => { + this.getUserData().then((userData) => { + this.emitChange(userData); + resolve(); + }); + }); + } + return unbindChange; + } + + public async getUserData() { + return (await this.http.get(`${this.settings.path}/userdata`)).data; } public async registerWithEmailAndPassword(email: string, password: string) { @@ -75,7 +90,7 @@ export class Auth { return data; } - public async oauth(providerName: string, settings: Partial = {}) { + public async signInWithProvider(providerName: string, settings: Partial = {}) { return new Promise((resolve, reject) => { const w = settings.width || 480; const h = settings.height || 768; @@ -123,7 +138,6 @@ export class Auth { } public async signOut() { - this.http.authToken = undefined; this.emitChange({ user: null, token: null }); } diff --git a/src/Client.ts b/src/Client.ts index 0e344a9..35c0bf1 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -227,7 +227,8 @@ export class Client { } protected getHttpEndpoint(segments: string = '') { - return `${(this.settings.secure) ? "https" : "http"}://${this.settings.hostname}${this.getEndpointPort()}${this.settings.pathname}/${segments}`; + const path = segments.startsWith("/") ? segments : `/${segments}`; + return `${(this.settings.secure) ? "https" : "http"}://${this.settings.hostname}${this.getEndpointPort()}${this.settings.pathname}${path}`; } protected getEndpointPort() { From 3869c1f2ed95fa0fa039ed298be2551d75d277a2 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 24 Nov 2023 14:57:32 -0300 Subject: [PATCH 08/15] auth: fix oauth rejection handling --- package.json | 2 +- src/Auth.ts | 43 ++++++++++++++++++++++++++++--------------- test/auth_test.ts | 30 ++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 test/auth_test.ts diff --git a/package.json b/package.json index 19f12ba..190aa80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.9", + "version": "0.15.15-preview.13", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index abab77d..b1d175c 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -44,18 +44,29 @@ export class Auth { public onChange(callback: (response: AuthData) => void) { const unbindChange = this.#_events.on("change", callback); if (!this.#_initialized) { - this.#_initializationPromise = new Promise((resolve, reject) => { + this.#_initializationPromise = new Promise((resolve, reject) => { this.getUserData().then((userData) => { this.emitChange(userData); + + }).catch((e) => { + // user is not logged in, or service is down + this.emitChange({ user: null, token: undefined }); + + }).finally(() => { resolve(); }); }); } + this.#_initialized = true; return unbindChange; } public async getUserData() { - return (await this.http.get(`${this.settings.path}/userdata`)).data; + if (this.token) { + return (await this.http.get(`${this.settings.path}/userdata`)).data; + } else { + throw new Error("missing auth.token"); + } } public async registerWithEmailAndPassword(email: string, password: string) { @@ -106,29 +117,30 @@ export class Auth { const onMessage = (event: MessageEvent) => { // TODO: it is a good idea to check if event.origin can be trusted! - debugger; // if (event.origin.indexOf(window.location.hostname) === -1) { return; } - console.log("popup, event =>", event); - console.log("popup, event.data =>", event.data); - // require 'user' and 'token' inside received data. - if (!event.data.user && !event.data.token) { return; } + if (event.data.user === undefined && event.data.token === undefined) { return; } clearInterval(rejectionChecker); this.#_signInWindow.close(); this.#_signInWindow = undefined; window.removeEventListener("message", onMessage); - resolve(event.data); - this.emitChange(event.data); + if (event.data.error !== undefined) { + reject(event.data.error); + + } else { + resolve(event.data); + this.emitChange(event.data); + } } const rejectionChecker = setInterval(() => { if (!this.#_signInWindow || this.#_signInWindow.closed) { this.#_signInWindow = undefined; - reject(); + reject("cancelled"); window.removeEventListener("message", onMessage); } }, 200); @@ -141,11 +153,12 @@ export class Auth { this.emitChange({ user: null, token: null }); } - private emitChange(authData: AuthData) { - this.token = authData.token; - - // store key in localStorage - setItem(this.settings.key, authData.token); + private emitChange(authData: Partial) { + if (authData.token !== undefined) { + this.token = authData.token; + // store key in localStorage + setItem(this.settings.key, authData.token); + } this.#_events.emit("change", authData); } diff --git a/test/auth_test.ts b/test/auth_test.ts new file mode 100644 index 0000000..07e05cf --- /dev/null +++ b/test/auth_test.ts @@ -0,0 +1,30 @@ +import './util'; +import assert from "assert"; +import { Client, Room } from "../src"; + +describe("Auth", function() { + let client: Client; + + before(() => { + client = new Client("ws://localhost:2546"); + }); + + describe("store token", () => { + it("should store token on localStorage", () => { + client.auth['emitChange']({ user: {}, token: "123" }); + assert.strictEqual("123", client.auth.token); + assert.strictEqual("123", window.localStorage.getItem(client.auth.settings.key)); + }); + + it("should reject if no token is stored", async () => { + // @ts-ignore + client.auth.token = undefined; + + await assert.rejects(async () => { + await client.auth.getUserData(); + }, /missing auth.token/); + }); + + }); + +}); From 264430dea06e7d633ea66d89cac78760131717ef Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 24 Nov 2023 17:45:10 -0300 Subject: [PATCH 09/15] oauth: use /auth/provider/:name by default --- package.json | 2 +- src/Auth.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 190aa80..f719328 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.13", + "version": "0.15.15-preview.15", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index b1d175c..4db767c 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -108,7 +108,7 @@ export class Auth { // Capitalize first letter of providerName const title = `Login with ${(providerName[0].toUpperCase() + providerName.substring(1))}`; - const url = this.http['client']['getHttpEndpoint'](`${(settings.prefix || "oauth")}/${providerName}`); + const url = this.http['client']['getHttpEndpoint'](`${(settings.prefix || `${this.settings.path}/provider`)}/${providerName}`); const left = (screen.width / 2) - (w / 2); const top = (screen.height / 2) - (h / 2); From 1de150336d964e8838878379392af927b847e974 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Sat, 25 Nov 2023 19:32:31 -0300 Subject: [PATCH 10/15] auth: make sure to emit 'token' + 'user' when requesting /userdata --- package.json | 2 +- src/Auth.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index f719328..80cbf30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.15", + "version": "0.15.15-preview.16", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index 4db767c..9ce2c2a 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -46,7 +46,7 @@ export class Auth { if (!this.#_initialized) { this.#_initializationPromise = new Promise((resolve, reject) => { this.getUserData().then((userData) => { - this.emitChange(userData); + this.emitChange({ ...userData, token: this.token }); }).catch((e) => { // user is not logged in, or service is down @@ -93,7 +93,7 @@ export class Auth { public async signInAnonymously() { const data = (await this.http.post(`${this.settings.path}/anonymous`, { - headers: { 'Content-Type': 'application/json' } + headers: { 'Content-Type': 'application/json' }, })).data; this.emitChange(data); From 8a767154006e9b2c6f9f447eb66e93dc4bc4cedd Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 28 Nov 2023 12:12:45 -0300 Subject: [PATCH 11/15] return ServerError if http request fails --- package.json | 2 +- src/Auth.ts | 12 +++++++++--- src/Client.ts | 1 + src/HTTP.ts | 17 ++++++++++++----- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 80cbf30..60cdb7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.16", + "version": "0.15.15-preview.18", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index 9ce2c2a..eaa5729 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -1,5 +1,5 @@ import { HTTP } from "./HTTP"; -import { getItem, setItem } from "./Storage"; +import { getItem, removeItem, setItem } from "./Storage"; import { createNanoEvents } from './core/nanoevents'; export interface AuthSettings { @@ -156,8 +156,14 @@ export class Auth { private emitChange(authData: Partial) { if (authData.token !== undefined) { this.token = authData.token; - // store key in localStorage - setItem(this.settings.key, authData.token); + + if (authData.token === null) { + removeItem(this.settings.key); + + } else { + // store key in localStorage + setItem(this.settings.key, authData.token); + } } this.#_events.emit("change", authData); diff --git a/src/Client.ts b/src/Client.ts index 35c0bf1..9c8401b 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -185,6 +185,7 @@ export class Client { }) ).data; + // FIXME: HTTP class is already handling this as ServerError. if (response.error) { throw new MatchMakeError(response.error, response.code); } diff --git a/src/HTTP.ts b/src/HTTP.ts index d11929e..b9cecb5 100644 --- a/src/HTTP.ts +++ b/src/HTTP.ts @@ -1,5 +1,6 @@ import { Client } from "./Client"; -import { post, get, put, del, Response, Options } from "httpie"; +import { ServerError } from "./errors/ServerError"; +import httpie, { Response, Options } from "httpie"; export class HTTP { public authToken: string; @@ -7,19 +8,25 @@ export class HTTP { constructor(protected client: Client) {} public get(path: string, options: Partial = {}): Promise> { - return get(this.client['getHttpEndpoint'](path), this.getOptions(options)); + return this.request("get", path, options); } public post(path: string, options: Partial = {}): Promise> { - return post(this.client['getHttpEndpoint'](path), this.getOptions(options)); + return this.request("post", path, options); } public del(path: string, options: Partial = {}): Promise> { - return del(this.client['getHttpEndpoint'](path), this.getOptions(options)); + return this.request("del", path, options); } public put(path: string, options: Partial = {}): Promise> { - return put(this.client['getHttpEndpoint'](path), this.getOptions(options)); + return this.request("put", path, options); + } + + protected request(method: "get" | "post" | "put" | "del", path: string, options: Partial = {}): Promise { + return httpie[method](this.client['getHttpEndpoint'](path), this.getOptions(options)).catch((e: any) => { + throw new ServerError(e.statusCode, e.data?.error || e.statusMessage || e.message); + }); } protected getOptions(options: Partial) { From d4ae580a5d3109ea24ee55f4326e2d245da07f0a Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 28 Nov 2023 18:09:01 -0300 Subject: [PATCH 12/15] auth: avoid sending 'application/json' as content'type twice --- package.json | 2 +- src/Auth.ts | 10 +++------- src/HTTP.ts | 14 +++++++------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 60cdb7e..96ce5fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.18", + "version": "0.15.15-preview.20", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index eaa5729..a68b9a0 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -69,10 +69,9 @@ export class Auth { } } - public async registerWithEmailAndPassword(email: string, password: string) { + public async registerWithEmailAndPassword(email: string, password: string, options?: any) { const data = (await this.http.post(`${this.settings.path}/register`, { - headers: { 'Content-Type': 'application/json' }, - body: { email, password, }, + body: { email, password, options, }, })).data; this.emitChange(data); @@ -82,7 +81,6 @@ export class Auth { public async signInWithEmailAndPassword(email: string, password: string) { const data = (await this.http.post(`${this.settings.path}/login`, { - headers: { 'Content-Type': 'application/json' }, body: { email, password, }, })).data; @@ -92,9 +90,7 @@ export class Auth { } public async signInAnonymously() { - const data = (await this.http.post(`${this.settings.path}/anonymous`, { - headers: { 'Content-Type': 'application/json' }, - })).data; + const data = (await this.http.post(`${this.settings.path}/anonymous`)).data; this.emitChange(data); diff --git a/src/HTTP.ts b/src/HTTP.ts index b9cecb5..2be89bb 100644 --- a/src/HTTP.ts +++ b/src/HTTP.ts @@ -1,35 +1,35 @@ import { Client } from "./Client"; import { ServerError } from "./errors/ServerError"; -import httpie, { Response, Options } from "httpie"; +import * as httpie from "httpie"; export class HTTP { public authToken: string; constructor(protected client: Client) {} - public get(path: string, options: Partial = {}): Promise> { + public get(path: string, options: Partial = {}): Promise> { return this.request("get", path, options); } - public post(path: string, options: Partial = {}): Promise> { + public post(path: string, options: Partial = {}): Promise> { return this.request("post", path, options); } - public del(path: string, options: Partial = {}): Promise> { + public del(path: string, options: Partial = {}): Promise> { return this.request("del", path, options); } - public put(path: string, options: Partial = {}): Promise> { + public put(path: string, options: Partial = {}): Promise> { return this.request("put", path, options); } - protected request(method: "get" | "post" | "put" | "del", path: string, options: Partial = {}): Promise { + protected request(method: "get" | "post" | "put" | "del", path: string, options: Partial = {}): Promise { return httpie[method](this.client['getHttpEndpoint'](path), this.getOptions(options)).catch((e: any) => { throw new ServerError(e.statusCode, e.data?.error || e.statusMessage || e.message); }); } - protected getOptions(options: Partial) { + protected getOptions(options: Partial) { if (this.authToken) { if (!options.headers) { options.headers = {}; From 0654bde21354b98209921dfc5c09c3d8bd4ade5e Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Tue, 5 Dec 2023 16:06:54 -0300 Subject: [PATCH 13/15] add auth.sendPasswordResetEmail() --- package.json | 2 +- src/Auth.ts | 16 ++++++++++++++-- src/HTTP.ts | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 96ce5fc..0a6b2a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.20", + "version": "0.15.15-preview.21", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index a68b9a0..a178910 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -89,8 +89,20 @@ export class Auth { return data; } - public async signInAnonymously() { - const data = (await this.http.post(`${this.settings.path}/anonymous`)).data; + public async signInAnonymously(options?: any) { + const data = (await this.http.post(`${this.settings.path}/anonymous`, { + body: { options, } + })).data; + + this.emitChange(data); + + return data; + } + + public async sendPasswordResetEmail(email: string) { + const data = (await this.http.post(`${this.settings.path}/forgot-password`, { + body: { email, } + })).data; this.emitChange(data); diff --git a/src/HTTP.ts b/src/HTTP.ts index 2be89bb..1007ebf 100644 --- a/src/HTTP.ts +++ b/src/HTTP.ts @@ -25,7 +25,7 @@ export class HTTP { protected request(method: "get" | "post" | "put" | "del", path: string, options: Partial = {}): Promise { return httpie[method](this.client['getHttpEndpoint'](path), this.getOptions(options)).catch((e: any) => { - throw new ServerError(e.statusCode, e.data?.error || e.statusMessage || e.message); + throw new ServerError(e.statusCode || -1, e.data?.error || e.statusMessage || e.message || "offline"); }); } From 9ad16b2368417a311b3d3c2c51e44ba6efd929f6 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 22 Dec 2023 10:34:59 -0300 Subject: [PATCH 14/15] auth: onChange test --- test/auth_test.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/auth_test.ts b/test/auth_test.ts index 07e05cf..44d5675 100644 --- a/test/auth_test.ts +++ b/test/auth_test.ts @@ -1,6 +1,7 @@ import './util'; import assert from "assert"; import { Client, Room } from "../src"; +import { AuthData } from '../src/Auth'; describe("Auth", function() { let client: Client; @@ -27,4 +28,20 @@ describe("Auth", function() { }); + describe("onChange", () => { + it("should trigger onChange when token is set", () => { + let onChangePayload: AuthData | undefined = undefined; + client.auth.onChange((data) => onChangePayload = data); + client.auth['emitChange']({ user: { dummy: true }, token: "123" }); + assert.strictEqual("123", client.auth.token); + assert.strictEqual("123", client.http.authToken); + + client.auth.onChange((data) => onChangePayload = data); + client.auth['emitChange']({ user: { dummy: true }, token: null } as any); + assert.strictEqual(null, client.auth.token); + assert.strictEqual(null, client.http.authToken); + }); + + }); + }); From 06986f2c70625a96fe58d34b34a3123d5cb64b41 Mon Sep 17 00:00:00 2001 From: Endel Dreyer Date: Fri, 22 Dec 2023 15:07:19 -0300 Subject: [PATCH 15/15] forward existing token during OAuth for upgrade. --- package.json | 2 +- src/Auth.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0a6b2a2..e0dbb42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "colyseus.js", - "version": "0.15.15-preview.21", + "version": "0.15.15-preview.22", "description": "Colyseus Multiplayer SDK for JavaScript/TypeScript", "author": "Endel Dreyer", "license": "MIT", diff --git a/src/Auth.ts b/src/Auth.ts index a178910..2c20df0 100644 --- a/src/Auth.ts +++ b/src/Auth.ts @@ -114,9 +114,12 @@ export class Auth { const w = settings.width || 480; const h = settings.height || 768; + // forward existing token for upgrading + const upgradingToken = this.token ? `?token=${this.token}` : ""; + // Capitalize first letter of providerName const title = `Login with ${(providerName[0].toUpperCase() + providerName.substring(1))}`; - const url = this.http['client']['getHttpEndpoint'](`${(settings.prefix || `${this.settings.path}/provider`)}/${providerName}`); + const url = this.http['client']['getHttpEndpoint'](`${(settings.prefix || `${this.settings.path}/provider`)}/${providerName}${upgradingToken}`); const left = (screen.width / 2) - (w / 2); const top = (screen.height / 2) - (h / 2);