mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:20:45 +00:00
Replace fetch with CapacitorHTTP
This commit is contained in:
Generated
+1
-25
@@ -32,7 +32,6 @@
|
||||
"binary-loader": "^0.0.1",
|
||||
"colord": "^2.9.3",
|
||||
"copy-webpack-plugin": "^13.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"d3": "^7.9.0",
|
||||
"dompurify": "^3.1.7",
|
||||
"dotenv": "^16.5.0",
|
||||
@@ -73,7 +72,6 @@
|
||||
"@eslint/compat": "^1.2.7",
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@types/chai": "^4.3.17",
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/jquery": "^3.5.31",
|
||||
@@ -9018,16 +9016,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
|
||||
"integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz",
|
||||
@@ -12047,19 +12035,6 @@
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
|
||||
@@ -18942,6 +18917,7 @@
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
"@eslint/compat": "^1.2.7",
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@types/chai": "^4.3.17",
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/jquery": "^3.5.31",
|
||||
@@ -106,7 +105,6 @@
|
||||
"binary-loader": "^0.0.1",
|
||||
"colord": "^2.9.3",
|
||||
"copy-webpack-plugin": "^13.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"d3": "^7.9.0",
|
||||
"dompurify": "^3.1.7",
|
||||
"dotenv": "^16.5.0",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CapacitorHttp } from "@capacitor/core";
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators.js";
|
||||
import randomMap from "../../resources/images/RandomMap.webp";
|
||||
@@ -472,12 +473,12 @@ export class HostLobbyModal extends LitElement {
|
||||
|
||||
private async putGameConfig() {
|
||||
const url = await buildGameUrl(this.lobbyId, "game");
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
const response = await CapacitorHttp.put({
|
||||
url: url,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: JSON.stringify({
|
||||
gameMap: this.selectedMap,
|
||||
difficulty: this.selectedDifficulty,
|
||||
disableNPCs: this.disableNPCs,
|
||||
@@ -519,8 +520,8 @@ export class HostLobbyModal extends LitElement {
|
||||
);
|
||||
this.close();
|
||||
const url = await buildGameUrl(this.lobbyId, "start_game");
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
const response = await CapacitorHttp.post({
|
||||
url,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
@@ -545,13 +546,13 @@ export class HostLobbyModal extends LitElement {
|
||||
|
||||
private async pollPlayers() {
|
||||
const url = await buildGameUrl(this.lobbyId, "game");
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
CapacitorHttp.get({
|
||||
url,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((response) => response.data)
|
||||
.then((data: GameInfo) => {
|
||||
console.log(`got game info response: ${JSON.stringify(data)}`);
|
||||
this.players = data.clients?.map((p) => p.username) ?? [];
|
||||
@@ -563,19 +564,19 @@ async function createLobby(): Promise<GameInfo> {
|
||||
try {
|
||||
const id = generateID();
|
||||
const url = await buildGameUrl(id, "create_game");
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
const response = await CapacitorHttp.post({
|
||||
url,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
// body: JSON.stringify(data), // Include this if you need to send data
|
||||
// data: JSON.stringify(data), // Include this if you need to send data
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (!response.data) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const data = response.data;
|
||||
console.log("Success:", data);
|
||||
|
||||
return data as GameInfo;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CapacitorHttp } from "@capacitor/core";
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators.js";
|
||||
import { translateText } from "../client/Utils";
|
||||
@@ -173,12 +174,12 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
private async checkActiveLobby(lobbyId: string): Promise<boolean> {
|
||||
const url = await buildGameUrl(lobbyId, "exists");
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
const response = await CapacitorHttp.get({
|
||||
url,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
const gameInfo = await response.json();
|
||||
const gameInfo = response.data;
|
||||
|
||||
if (gameInfo.exists) {
|
||||
this.message = translateText("private_lobby.joined_waiting");
|
||||
@@ -205,12 +206,12 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
private async checkArchivedGame(lobbyId: string): Promise<boolean> {
|
||||
const url = await buildGameUrl(lobbyId, "archived_game");
|
||||
|
||||
const archiveResponse = await fetch(url, {
|
||||
method: "GET",
|
||||
const archiveResponse = await CapacitorHttp.get({
|
||||
url,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
const archiveData = await archiveResponse.json();
|
||||
const archiveData = archiveResponse.data;
|
||||
|
||||
if (
|
||||
archiveData.success === false &&
|
||||
@@ -250,13 +251,13 @@ export class JoinPrivateLobbyModal extends LitElement {
|
||||
if (!this.lobbyIdInput?.value) return;
|
||||
|
||||
const url = await buildGameUrl(this.lobbyIdInput.value, "game");
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
CapacitorHttp.get({
|
||||
url,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((response) => JSON.parse(response.data))
|
||||
.then((data: GameInfo) => {
|
||||
this.players = data.clients?.map((p) => p.username) ?? [];
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CapacitorHttp } from "@capacitor/core";
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { resolveMarkdown } from "lit-markdown";
|
||||
import { customElement, property, query } from "lit/decorators.js";
|
||||
@@ -87,8 +88,12 @@ export class NewsModal extends LitElement {
|
||||
public open() {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
fetch(changelog)
|
||||
.then((response) => (response.ok ? response.text() : "Failed to load"))
|
||||
CapacitorHttp.get({
|
||||
url: `${process.env.APP_BASE_URL || ""}${changelog}`,
|
||||
})
|
||||
.then((response) =>
|
||||
response.status === 200 ? response.data : "Failed to load",
|
||||
)
|
||||
.then((markdown) => (this.markdown = markdown));
|
||||
}
|
||||
this.requestUpdate();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CapacitorHttp } from "@capacitor/core";
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { translateText } from "../client/Utils";
|
||||
@@ -56,12 +57,13 @@ export class PublicLobby extends LitElement {
|
||||
|
||||
async fetchLobbies(): Promise<GameInfo[]> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${process.env.APP_BASE_URL || ""}/api/public_lobbies`,
|
||||
);
|
||||
if (!response.ok)
|
||||
const response = await CapacitorHttp.get({
|
||||
url: `${process.env.APP_BASE_URL || ""}/api/public_lobbies`,
|
||||
});
|
||||
|
||||
if (response.status !== 200)
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
const data = await response.json();
|
||||
const data = JSON.parse(response.data);
|
||||
return data.lobbies;
|
||||
} catch (error) {
|
||||
console.error("Error fetching lobbies:", error);
|
||||
|
||||
+13
-15
@@ -1,6 +1,6 @@
|
||||
import { App } from "@capacitor/app";
|
||||
import { Browser } from "@capacitor/browser";
|
||||
import { Capacitor } from "@capacitor/core";
|
||||
import { Capacitor, CapacitorHttp } from "@capacitor/core";
|
||||
import { decodeJwt } from "jose";
|
||||
import { z } from "zod/v4";
|
||||
import {
|
||||
@@ -139,17 +139,14 @@ export async function logOut(allSessions: boolean = false) {
|
||||
localStorage.removeItem("token");
|
||||
__isLoggedIn = false;
|
||||
|
||||
const response = await fetch(
|
||||
getApiBase() + (allSessions ? "/revoke" : "/logout"),
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
authorization: `Bearer ${token}`,
|
||||
},
|
||||
const response = await CapacitorHttp.post({
|
||||
url: getApiBase() + (allSessions ? "/revoke" : "/logout"),
|
||||
headers: {
|
||||
authorization: `Bearer ${token}`,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
if (response.ok === false) {
|
||||
if (response.status !== 200) {
|
||||
console.error("Logout failed", response);
|
||||
return false;
|
||||
}
|
||||
@@ -254,8 +251,8 @@ export async function postRefresh(): Promise<boolean> {
|
||||
if (!token) return false;
|
||||
|
||||
// Refresh the JWT
|
||||
const response = await fetch(getApiBase() + "/refresh", {
|
||||
method: "POST",
|
||||
const response = await CapacitorHttp.post({
|
||||
url: getApiBase() + "/refresh",
|
||||
headers: {
|
||||
authorization: `Bearer ${token}`,
|
||||
},
|
||||
@@ -266,7 +263,7 @@ export async function postRefresh(): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
if (response.status !== 200) return false;
|
||||
const body = await response.json();
|
||||
const body = response.data;
|
||||
const result = RefreshResponseSchema.safeParse(body);
|
||||
if (!result.success) {
|
||||
const error = z.prettifyError(result.error);
|
||||
@@ -287,7 +284,8 @@ export async function getUserMe(): Promise<UserMeResponse | false> {
|
||||
if (!token) return false;
|
||||
|
||||
// Get the user object
|
||||
const response = await fetch(getApiBase() + "/users/@me", {
|
||||
const response = await CapacitorHttp.get({
|
||||
url: getApiBase() + "/users/@me",
|
||||
headers: {
|
||||
authorization: `Bearer ${token}`,
|
||||
},
|
||||
@@ -298,7 +296,7 @@ export async function getUserMe(): Promise<UserMeResponse | false> {
|
||||
return false;
|
||||
}
|
||||
if (response.status !== 200) return false;
|
||||
const body = await response.json();
|
||||
const body = response.data;
|
||||
const result = UserMeResponseSchema.safeParse(body);
|
||||
if (!result.success) {
|
||||
const error = z.prettifyError(result.error);
|
||||
|
||||
@@ -62,7 +62,6 @@ export interface ServerConfig {
|
||||
cloudflareApiToken(): string;
|
||||
cloudflareConfigPath(): string;
|
||||
cloudflareCredsPath(): string;
|
||||
origin(): string;
|
||||
}
|
||||
|
||||
export interface NukeMagnitude {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CapacitorHttp } from "@capacitor/core";
|
||||
import { UserSettings } from "../game/UserSettings";
|
||||
import { GameConfig } from "../Schemas";
|
||||
import { Config, GameEnv, ServerConfig } from "./Config";
|
||||
@@ -29,19 +30,52 @@ export async function getServerConfigFromClient(): Promise<ServerConfig> {
|
||||
if (cachedSC) {
|
||||
return cachedSC;
|
||||
}
|
||||
const response = await fetch(`${process.env.APP_BASE_URL || ""}/api/env`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch server config: ${response.status} ${response.statusText}`,
|
||||
try {
|
||||
const response = await CapacitorHttp.get({
|
||||
url: `${process.env.APP_BASE_URL || ""}/api/env`,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error(`Failed to fetch server config: ${response.status}`);
|
||||
}
|
||||
|
||||
// Check if response is HTML (error case)
|
||||
const dataStr =
|
||||
typeof response.data === "string"
|
||||
? response.data
|
||||
: JSON.stringify(response.data);
|
||||
if (dataStr.includes("<!doctype html>") || dataStr.includes("<html")) {
|
||||
console.warn(
|
||||
"Server returned HTML instead of JSON, falling back to environment variable",
|
||||
);
|
||||
return getServerConfigFromServer();
|
||||
}
|
||||
|
||||
const config = response.data;
|
||||
|
||||
// Validate that we got the expected structure
|
||||
if (!config || typeof config.game_env !== "string") {
|
||||
console.warn(
|
||||
"Invalid config structure received, falling back to environment variable",
|
||||
);
|
||||
return getServerConfigFromServer();
|
||||
}
|
||||
|
||||
console.log("Server config loaded:", config);
|
||||
|
||||
cachedSC = getServerConfig(config.game_env);
|
||||
return cachedSC;
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"Error fetching server config from API, falling back to environment variable:",
|
||||
error,
|
||||
);
|
||||
return getServerConfigFromServer();
|
||||
}
|
||||
const config = await response.json();
|
||||
// Log the retrieved configuration
|
||||
console.log("Server config loaded:", config);
|
||||
|
||||
cachedSC = getServerConfig(config.game_env);
|
||||
return cachedSC;
|
||||
}
|
||||
export function getServerConfigFromServer(): ServerConfig {
|
||||
const gameEnv = process.env.GAME_ENV ?? "dev";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CapacitorHttp } from "@capacitor/core";
|
||||
import { JWK } from "jose";
|
||||
import { z } from "zod/v4";
|
||||
import {
|
||||
@@ -85,18 +86,6 @@ export abstract class DefaultServerConfig implements ServerConfig {
|
||||
return process.env.CF_CREDS_PATH ?? "";
|
||||
}
|
||||
|
||||
origin(): string {
|
||||
const audience = this.jwtAudience();
|
||||
const subdomain = this.subdomain();
|
||||
if (audience === "localhost") {
|
||||
return "http://localhost:9000";
|
||||
}
|
||||
if (subdomain === "") {
|
||||
return `https://${audience}`;
|
||||
}
|
||||
return `https://${subdomain}.${audience}`;
|
||||
}
|
||||
|
||||
private publicKey: JWK;
|
||||
abstract jwtAudience(): string;
|
||||
jwtIssuer(): string {
|
||||
@@ -109,8 +98,10 @@ export abstract class DefaultServerConfig implements ServerConfig {
|
||||
if (this.publicKey) return this.publicKey;
|
||||
const jwksUrl = this.jwtIssuer() + "/.well-known/jwks.json";
|
||||
console.log(`Fetching JWKS from ${jwksUrl}`);
|
||||
const response = await fetch(jwksUrl);
|
||||
const result = JwksSchema.safeParse(await response.json());
|
||||
const response = await CapacitorHttp.get({
|
||||
url: jwksUrl,
|
||||
});
|
||||
const result = JwksSchema.safeParse(response.data);
|
||||
if (!result.success) {
|
||||
const error = z.prettifyError(result.error);
|
||||
console.error("Error parsing JWKS", error);
|
||||
|
||||
@@ -7,7 +7,6 @@ import { fileURLToPath } from "url";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { GameInfo } from "../core/Schemas";
|
||||
import { generateID } from "../core/Util";
|
||||
import { corsMiddleware } from "./cors";
|
||||
import { gatekeeper, LimiterType } from "./Gatekeeper";
|
||||
import { logger } from "./Logger";
|
||||
import { MapPlaylist } from "./MapPlaylist";
|
||||
@@ -24,7 +23,6 @@ const log = logger.child({ comp: "m" });
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
app.use(corsMiddleware);
|
||||
app.use(
|
||||
express.static(path.join(__dirname, "../../static"), {
|
||||
maxAge: "1y", // Set max-age to 1 year for all static assets
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
import { CreateGameInputSchema, GameInputSchema } from "../core/WorkerSchemas";
|
||||
import { archive, readGameRecord } from "./Archive";
|
||||
import { Client } from "./Client";
|
||||
import { corsMiddleware } from "./cors";
|
||||
import { GameManager } from "./GameManager";
|
||||
import { gatekeeper, LimiterType } from "./Gatekeeper";
|
||||
import { getUserMe, verifyClientToken } from "./jwt";
|
||||
@@ -72,7 +71,6 @@ export function startWorker() {
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(corsMiddleware);
|
||||
app.set("trust proxy", 3);
|
||||
app.use(express.json());
|
||||
app.use(express.static(path.join(__dirname, "../../out")));
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import cors from "cors";
|
||||
import { GameEnv } from "../core/configuration/Config";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
|
||||
const config = getServerConfigFromServer();
|
||||
const origin = config.origin();
|
||||
|
||||
const allowedOriginsSet = new Set<string>([origin]);
|
||||
|
||||
switch (config.env()) {
|
||||
case GameEnv.Prod:
|
||||
allowedOriginsSet.add("capacitor://openfront.io");
|
||||
allowedOriginsSet.add("https://openfront.io");
|
||||
break;
|
||||
case GameEnv.Preprod:
|
||||
allowedOriginsSet.add("capacitor://openfront.dev");
|
||||
allowedOriginsSet.add("https://openfront.dev");
|
||||
break;
|
||||
case GameEnv.Dev: {
|
||||
allowedOriginsSet.add("capacitor://localhost");
|
||||
allowedOriginsSet.add("http://localhost");
|
||||
allowedOriginsSet.add("http://localhost:8787");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const allowedOrigins = Array.from(allowedOriginsSet);
|
||||
|
||||
const corsOptions = {
|
||||
origin: (
|
||||
origin: string | undefined,
|
||||
callback: (err: Error | null, allow?: boolean) => void,
|
||||
) => {
|
||||
// allow requests with no origin (like mobile apps or curl requests)
|
||||
if (!origin) return callback(null, true);
|
||||
if (allowedOrigins.some((o) => origin.startsWith(o))) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
callback(new Error("Not allowed by CORS"));
|
||||
}
|
||||
},
|
||||
credentials: true,
|
||||
};
|
||||
|
||||
export const corsMiddleware = cors(corsOptions);
|
||||
@@ -4,9 +4,6 @@ import { GameMapType } from "../../src/core/game/Game";
|
||||
import { GameID } from "../../src/core/Schemas";
|
||||
|
||||
export class TestServerConfig implements ServerConfig {
|
||||
origin(): string {
|
||||
return "unused";
|
||||
}
|
||||
cloudflareConfigPath(): string {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user