Skip to content

Commit bc9532b

Browse files
authored
dev: update handling of dev and beta modes (#1400)
* Update handling of dev and beta modes - Replace the `start` command in `package.json` with `start:prod` and `start:beta`, which run the game in "production" and "beta" mode respectively Previously, `start` would run the game in "development" mode just like `start:dev` due to the `vite` command running in "development" mode by default if no `--mode` arg was passed - Add `IS_DEV` global constant that checks for "development" mode - Remove `Api#isLocal` and replace its uses with `BYPASS_LOGIN` - Add " (Beta)" to window title and game version displayed on the title screen when in "development" or "beta" mode - Replace `.then()` pattern with `await` in `main.ts` - Remove obsolete commented code in `game-data.ts` * Add return types for api methods, update some docs/comments * Update `deploy-beta.yml` workflow to use "beta" mode when building
1 parent b68591b commit bc9532b

18 files changed

+116
-153
lines changed

.github/workflows/deploy-beta.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
- name: Build
3131
run: pnpm build:beta
3232
env:
33-
NODE_ENV: production
33+
NODE_ENV: beta
3434

3535
- name: Set up SSH
3636
run: |

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"version": "0.1.0",
55
"type": "module",
66
"scripts": {
7-
"start": "vite",
7+
"start:prod": "vite --mode production",
8+
"start:beta": "vite --mode beta",
89
"start:dev": "vite --mode development",
910
"build": "vite build",
1011
"build:beta": "vite build --mode beta",

src/constants/app-constants.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,19 @@ export const RUN_HISTORY_LIMIT: number = 25;
6464
/** The number of save slots available to players. */
6565
export const SAVE_SLOT_LIMIT: number = 5;
6666

67-
/** Whether the app is running in beta (or development) mode. */
67+
/**
68+
* `true` if running in "beta" mode via either of:
69+
* - `pnpm start:beta` (which runs `vite --mode beta`)
70+
* - A build created via `pnpm build:beta`
71+
*/
6872
export const IS_BETA = import.meta.env.MODE === "beta";
6973

74+
/**
75+
* `true` if running in "development" mode via either of:
76+
* - `pnpm start:dev` (which runs `vite --mode development`)
77+
* - A build created via `pnpm build:dev`
78+
*/
79+
export const IS_DEV = import.meta.env.MODE === "development";
80+
7081
/** Whether the app is running in a test environment */
7182
export const IS_TEST = import.meta.env.NODE_ENV === "test";

src/main.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import "#app/polyfills"; // polyfills must be first
22
import "#app/phaser-extensions";
33

4-
// Catch global errors and display them in an alert so users can report the issue.
4+
import { IS_BETA, IS_DEV } from "#constants/app-constants";
5+
6+
if (IS_DEV || IS_BETA) {
7+
document.title += " (Beta)";
8+
}
9+
510
window.onerror = (_message, _source, _lineno, _colno, error) => {
611
console.error(error);
7-
// const errorString = `Received unhandled error. Open browser console and click OK to see details.\nError: ${message}\nSource: ${source}\nLine: ${lineno}\nColumn: ${colno}\nStack: ${error.stack}`;
8-
//alert(errorString);
912
// Avoids logging the error a second time.
1013
return true;
1114
};
1215

13-
// Catch global promise rejections and display them in an alert so users can report the issue.
1416
window.addEventListener("unhandledrejection", (event) => {
15-
// const errorString = `Received unhandled promise rejection. Open browser console and click OK to see details.\nReason: ${event.reason}`;
1617
console.error(event.reason);
17-
//alert(errorString);
1818
});
1919

2020
document.fonts.load("16px emerald").then(() => document.fonts.load("10px pkmnems"));
@@ -36,17 +36,14 @@ const startGame = async (manifest?: any) => {
3636
}
3737
};
3838

39-
fetch("/manifest.json")
40-
.then((res) => res.json())
41-
.then((jsonResponse) => {
42-
startGame(jsonResponse.manifest);
43-
})
44-
.catch(() => {
45-
// Manifest not found (likely local build)
46-
startGame();
47-
})
48-
.finally(() => {
49-
if (import.meta.env.MODE === "development") {
50-
import("./dev");
51-
}
52-
});
39+
try {
40+
const json = await (await fetch("/manifest.json")).json();
41+
await startGame(json.manifest);
42+
} catch {
43+
// The manifest wasn't found, likely due to running locally
44+
await startGame();
45+
}
46+
47+
if (IS_DEV) {
48+
await import("./dev");
49+
}

src/phases/game-over-phase.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { api } from "#api/api";
22
import { clientSessionId } from "#app/account";
33
import { globalScene } from "#app/global-scene";
4+
import { BYPASS_LOGIN } from "#constants/app-constants";
45
import { getCharVariantFromDialogue } from "#data/dialogue";
56
import type { PokemonSpecies } from "#data/pokemon-species";
67
import { AchvCategory } from "#enums/achv-category";
@@ -200,12 +201,9 @@ export class GameOverPhase extends BattlePhase {
200201
});
201202
};
202203

203-
/**
204-
* Check to see if the game is running offline
205-
* If Online, execute apiFetch as intended
206-
* If Offline, execute offlineNewClear() only for victory, a localStorage implementation of newClear daily run checks
207-
*/
208-
if (!api.isLocal || api.isConnected) {
204+
// If Online, execute `apiFetch` as intended
205+
// If Offline, execute `offlineNewClear()` only for victory, a localStorage implementation of `newClear` daily run checks
206+
if (!BYPASS_LOGIN || api.isConnected) {
209207
api.savedata.session
210208
.newclear({ slot: globalScene.sessionSlotId, isVictory: this.isVictory, clientSessionId })
211209
.then((success) => doGameOver(success));

src/phases/title-phase.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { loggedInUser } from "#app/account";
33
import { getGameMode, getModeName } from "#app/game-mode";
44
import { globalScene } from "#app/global-scene";
55
import { Phase } from "#app/phase";
6+
import { BYPASS_LOGIN } from "#constants/app-constants";
67
import { fetchDailyRunSeed, getDailyRunStarters } from "#data/daily-run";
78
import { GameModes } from "#enums/game-modes";
89
import { ModifierPoolType } from "#enums/modifier-pool-type";
@@ -247,8 +248,9 @@ export class TitlePhase extends Phase {
247248
});
248249
};
249250

250-
// If Online, calls seed fetch from db to generate daily run. If Offline, generates a daily run based on current date.
251-
if (!api.isLocal || api.isConnected) {
251+
// If Online, calls seed fetch from db to generate daily run.
252+
// If Offline, generates a daily run based on current date.
253+
if (!BYPASS_LOGIN || api.isConnected) {
252254
fetchDailyRunSeed()
253255
.then((seed) => {
254256
if (seed) {

src/plugins/api/account-api.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import type {
88
} from "#types/api-types";
99
import { removeCookie, setCookie } from "#utils/app-utils";
1010

11-
/**
12-
* A wrapper for the account API requests.
13-
*/
11+
/** A wrapper for the account API requests. */
1412
export class AccountApi extends ApiBase {
1513
//#region Public
1614

@@ -39,7 +37,7 @@ export class AccountApi extends ApiBase {
3937
* @param registerData The {@linkcode AccountRegisterRequest} to send
4038
* @returns An error message if something went wrong
4139
*/
42-
public async register(registerData: AccountRegisterRequest) {
40+
public async register(registerData: AccountRegisterRequest): Promise<string | null> {
4341
try {
4442
const response = await this.doPost("/account/register", registerData, "form-urlencoded");
4543

@@ -60,7 +58,7 @@ export class AccountApi extends ApiBase {
6058
* @param loginData The {@linkcode AccountLoginRequest} to send
6159
* @returns An error message if something went wrong
6260
*/
63-
public async login(loginData: AccountLoginRequest) {
61+
public async login(loginData: AccountLoginRequest): Promise<string | null> {
6462
try {
6563
const response = await this.doPost("/account/login", loginData, "form-urlencoded");
6664

@@ -82,7 +80,7 @@ export class AccountApi extends ApiBase {
8280
* Send a logout request.
8381
* **Always** (no matter if failed or not) removes the session cookie.
8482
*/
85-
public async logout() {
83+
public async logout(): Promise<void> {
8684
try {
8785
const response = await this.doGet("/account/logout");
8886

@@ -95,4 +93,6 @@ export class AccountApi extends ApiBase {
9593

9694
removeCookie(SESSION_ID_COOKIE); // we are always clearing the cookie.
9795
}
96+
97+
//#endregion
9898
}

src/plugins/api/admin-api.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export class AdminApi extends ApiBase {
1616
* @param params The {@linkcode LinkAccountToDiscordIdRequest} to send
1717
* @returns `null` if successful, error message if not
1818
*/
19-
public async linkAccountToDiscord(params: LinkAccountToDiscordIdRequest) {
19+
public async linkAccountToDiscord(params: LinkAccountToDiscordIdRequest): Promise<string | null> {
2020
try {
2121
const response = await this.doPost("/admin/account/discordLink", params, "form-urlencoded");
2222

@@ -40,7 +40,7 @@ export class AdminApi extends ApiBase {
4040
* @param params The {@linkcode UnlinkAccountFromDiscordIdRequest} to send
4141
* @returns `null` if successful, error message if not
4242
*/
43-
public async unlinkAccountFromDiscord(params: UnlinkAccountFromDiscordIdRequest) {
43+
public async unlinkAccountFromDiscord(params: UnlinkAccountFromDiscordIdRequest): Promise<string | null> {
4444
try {
4545
const response = await this.doPost("/admin/account/discordUnlink", params, "form-urlencoded");
4646

@@ -64,7 +64,7 @@ export class AdminApi extends ApiBase {
6464
* @param params The {@linkcode LinkAccountToGoogledIdRequest} to send
6565
* @returns `null` if successful, error message if not
6666
*/
67-
public async linkAccountToGoogleId(params: LinkAccountToGoogledIdRequest) {
67+
public async linkAccountToGoogleId(params: LinkAccountToGoogledIdRequest): Promise<string | null> {
6868
try {
6969
const response = await this.doPost("/admin/account/googleLink", params, "form-urlencoded");
7070

@@ -88,7 +88,7 @@ export class AdminApi extends ApiBase {
8888
* @param params The {@linkcode UnlinkAccountFromGoogledIdRequest} to send
8989
* @returns `null` if successful, error message if not
9090
*/
91-
public async unlinkAccountFromGoogleId(params: UnlinkAccountFromGoogledIdRequest) {
91+
public async unlinkAccountFromGoogleId(params: UnlinkAccountFromGoogledIdRequest): Promise<string | null> {
9292
try {
9393
const response = await this.doPost("/admin/account/googleUnlink", params, "form-urlencoded");
9494

src/plugins/api/api-base.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,21 @@ export abstract class ApiBase {
1010

1111
protected readonly base: string;
1212

13+
//#endregion
1314
//#region Public
1415

1516
constructor(base: string) {
1617
this.base = base;
1718
}
1819

20+
//#endregion
1921
//#region Protected
2022

2123
/**
2224
* Send a GET request.
2325
* @param path The path to send the request to.
2426
*/
25-
protected async doGet(path: string) {
27+
protected async doGet(path: string): Promise<Response> {
2628
return this.doFetch(path, { method: "GET" });
2729
}
2830

@@ -32,7 +34,7 @@ export abstract class ApiBase {
3234
* @param bodyData The body-data to send.
3335
* @param dataType The data-type of the {@linkcode bodyData}.
3436
*/
35-
protected async doPost<D = undefined>(path: string, bodyData?: D, dataType: DataType = "json") {
37+
protected async doPost<D = undefined>(path: string, bodyData?: D, dataType: DataType = "json"): Promise<Response> {
3638
let body: string | undefined;
3739
const headers: HeadersInit = {};
3840

@@ -83,11 +85,13 @@ export abstract class ApiBase {
8385
* @param data the data to transform to {@linkcode URLSearchParams}
8486
* @returns a {@linkcode URLSearchParams} representaton of {@linkcode data}
8587
*/
86-
protected toUrlSearchParams<D extends Record<string, any>>(data: D) {
88+
protected toUrlSearchParams<D extends Record<string, any>>(data: D): URLSearchParams {
8789
const arr = Object.entries(data)
8890
.map(([key, value]) => [key, String(value ?? "")])
8991
.filter(([, value]) => value !== "");
9092

9193
return new URLSearchParams(arr);
9294
}
95+
96+
//#endregion
9397
}

src/plugins/api/api.ts

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ import { DailyApi } from "#api/daily-api";
55
import { SavedataApi } from "#api/savedata-api";
66
import type { TitleStatsResponse } from "#types/api-types";
77

8-
/**
9-
* A wrapper for API requests.
10-
*/
8+
/** A wrapper for API requests. */
119
class Api extends ApiBase {
1210
//#region Fields
1311

@@ -18,11 +16,10 @@ class Api extends ApiBase {
1816
public readonly admin: AdminApi;
1917
public readonly savedata: SavedataApi;
2018

21-
/** Wheter the hostname is 'localhost' or an IP address, and ensure a port is specified. */
22-
private readonly _isLocal: boolean;
2319
/** Whether the server/api is connected. By default we assume `true`. */
2420
private _isConnected: boolean;
2521

22+
//#endregion
2623
//#region Public
2724

2825
constructor(base: string) {
@@ -31,26 +28,17 @@ class Api extends ApiBase {
3128
this.daily = new DailyApi(base);
3229
this.admin = new AdminApi(base);
3330
this.savedata = new SavedataApi(base);
34-
this._isLocal =
35-
((window.location.hostname === "localhost" || /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/.test(window.location.hostname))
36-
&& window.location.port !== "")
37-
|| window.location.hostname === "";
3831
}
3932

4033
/** Whether the server/api is connected. By default we assume `true`. */
41-
public get isConnected() {
34+
public get isConnected(): boolean {
4235
return this._isConnected;
4336
}
4437

45-
/** Wheter the hostname is 'localhost' or an IP address, and ensure a port is specified. */
46-
public get isLocal() {
47-
return this._isLocal;
48-
}
49-
5038
/**
5139
* Request game title-stats.
5240
*/
53-
public async getGameTitleStats() {
41+
public async getGameTitleStats(): Promise<TitleStatsResponse | null> {
5442
if (!this.isConnected) {
5543
this.printServerNotConnectedWarning();
5644
return null;
@@ -69,7 +57,7 @@ class Api extends ApiBase {
6957
* Unlink the currently logged in user from Discord.
7058
* @returns `true` if unlinking was successful, `false` if not
7159
*/
72-
public async unlinkDiscord() {
60+
public async unlinkDiscord(): Promise<boolean> {
7361
if (!this.isConnected) {
7462
this.printServerNotConnectedWarning();
7563
return false;
@@ -92,7 +80,7 @@ class Api extends ApiBase {
9280
* Unlink the currently logged in user from Google.
9381
* @returns `true` if unlinking was successful, `false` if not
9482
*/
95-
public async unlinkGoogle() {
83+
public async unlinkGoogle(): Promise<boolean> {
9684
if (!this.isConnected) {
9785
this.printServerNotConnectedWarning();
9886
return false;
@@ -116,7 +104,7 @@ class Api extends ApiBase {
116104
* @remarks
117105
* We have no dedicated ping/status endpoint yet, so we ping the game title stats endpoint, but without printing any errors by default.
118106
*/
119-
async ping() {
107+
public async ping(): Promise<void> {
120108
try {
121109
const response = await this.doGet("/game/titlestats");
122110
const data = await response.json();
@@ -129,14 +117,14 @@ class Api extends ApiBase {
129117
}
130118
}
131119
if (import.meta.env.VITE_API_DEBUG === "1") {
132-
console.log("isLocalServerConnected:", this.isConnected);
120+
console.log("`Api#isConnected`:", this.isConnected);
133121
}
134122
}
135123

136124
//#endregion
137125
//#region Private
138126

139-
private printServerNotConnectedWarning() {
127+
private printServerNotConnectedWarning(): void {
140128
if (import.meta.env.VITE_API_DEBUG === "1") {
141129
console.warn(this.ERR_SERVER_NOT_CONNECTED);
142130
}

0 commit comments

Comments
 (0)