120 lines
3.6 KiB
JavaScript
120 lines
3.6 KiB
JavaScript
// API Communication and State Sync
|
|
const API = {
|
|
tokenKey: 'el_puro_jwt_token',
|
|
userKey: 'el_puro_username',
|
|
|
|
getToken() {
|
|
return localStorage.getItem(this.tokenKey);
|
|
},
|
|
|
|
getUsername() {
|
|
return localStorage.getItem(this.userKey);
|
|
},
|
|
|
|
setAuth(token, username) {
|
|
localStorage.setItem(this.tokenKey, token);
|
|
localStorage.setItem(this.userKey, username);
|
|
},
|
|
|
|
logout() {
|
|
localStorage.removeItem(this.tokenKey);
|
|
localStorage.removeItem(this.userKey);
|
|
},
|
|
|
|
async register(username, password, websiteHp = '') {
|
|
const res = await fetch('/api/auth/register', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
username,
|
|
password,
|
|
website_hp: websiteHp
|
|
})
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({ detail: 'Registration failed' }));
|
|
throw new Error(err.detail || 'Registration failed');
|
|
}
|
|
const data = await res.json();
|
|
this.setAuth(data.token, data.username);
|
|
return data;
|
|
},
|
|
|
|
async login(username, password) {
|
|
const res = await fetch('/api/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ username, password })
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({ detail: 'Invalid credentials' }));
|
|
throw new Error(err.detail || 'Login failed');
|
|
}
|
|
const data = await res.json();
|
|
this.setAuth(data.token, data.username);
|
|
return data;
|
|
},
|
|
|
|
async loadRemoteSave() {
|
|
const token = this.getToken();
|
|
if (!token) return null;
|
|
|
|
try {
|
|
const res = await fetch('/api/game/state', {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
if (!res.ok) {
|
|
if (res.status === 401) this.logout();
|
|
return null;
|
|
}
|
|
const data = await res.json();
|
|
return data.has_save ? data.save_data : null;
|
|
} catch (e) {
|
|
console.warn('Network issue loading cloud save, fallback to local', e);
|
|
return null;
|
|
}
|
|
},
|
|
|
|
async syncTick(actions = []) {
|
|
const token = this.getToken();
|
|
if (!token) return null;
|
|
|
|
try {
|
|
const res = await fetch('/api/game/tick', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${token}`
|
|
},
|
|
body: JSON.stringify({ actions })
|
|
});
|
|
if (!res.ok) {
|
|
if (res.status === 401) this.logout();
|
|
return null;
|
|
}
|
|
const data = await res.json();
|
|
return data.save_data;
|
|
} catch (e) {
|
|
console.warn('Network tick failed, queuing actions', e);
|
|
return null;
|
|
}
|
|
},
|
|
|
|
async saveRemote(saveData) {
|
|
const token = this.getToken();
|
|
if (!token) return;
|
|
|
|
try {
|
|
await fetch('/api/game/save', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${token}`
|
|
},
|
|
body: JSON.stringify({ save_data: saveData })
|
|
});
|
|
} catch (e) {
|
|
console.warn('Failed cloud save sync', e);
|
|
}
|
|
}
|
|
};
|