Add commandId generation for idempotent requests in API calls
This commit is contained in:
@@ -8,6 +8,11 @@ const API_URL = import.meta.env.VITE_API_URL ||
|
|||||||
console.log('🔌 WebSocket URL:', WS_URL);
|
console.log('🔌 WebSocket URL:', WS_URL);
|
||||||
console.log('📡 API URL:', API_URL);
|
console.log('📡 API URL:', API_URL);
|
||||||
|
|
||||||
|
// Generate a unique command ID for idempotent requests
|
||||||
|
function newCommandId() {
|
||||||
|
return crypto.randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
// ========== Timers (module-level so they survive store re-creates) ==========
|
// ========== Timers (module-level so they survive store re-creates) ==========
|
||||||
let _httpPollTimer = null;
|
let _httpPollTimer = null;
|
||||||
let _wsHealthTimer = null;
|
let _wsHealthTimer = null;
|
||||||
@@ -183,7 +188,7 @@ export const useInventoryStore = create((set, get) => ({
|
|||||||
const response = await fetch(`${API_URL}/order`, {
|
const response = await fetch(`${API_URL}/order`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ itemName, amount, dropperName }),
|
body: JSON.stringify({ itemName, amount, dropperName, commandId: newCommandId() }),
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -194,7 +199,11 @@ export const useInventoryStore = create((set, get) => ({
|
|||||||
|
|
||||||
requestScan: async () => {
|
requestScan: async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_URL}/scan`, { method: 'POST' });
|
const response = await fetch(`${API_URL}/scan`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ commandId: newCommandId() }),
|
||||||
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error requesting scan:', error);
|
console.error('❌ Error requesting scan:', error);
|
||||||
@@ -204,7 +213,11 @@ export const useInventoryStore = create((set, get) => ({
|
|||||||
|
|
||||||
toggleSmelting: async () => {
|
toggleSmelting: async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_URL}/smelting/toggle`, { method: 'POST' });
|
const response = await fetch(`${API_URL}/smelting/toggle`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ commandId: newCommandId() }),
|
||||||
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error toggling smelting:', error);
|
console.error('❌ Error toggling smelting:', error);
|
||||||
@@ -217,7 +230,7 @@ export const useInventoryStore = create((set, get) => ({
|
|||||||
const response = await fetch(`${API_URL}/recipes/toggle`, {
|
const response = await fetch(`${API_URL}/recipes/toggle`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ recipe }),
|
body: JSON.stringify({ recipe, commandId: newCommandId() }),
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -228,7 +241,11 @@ export const useInventoryStore = create((set, get) => ({
|
|||||||
|
|
||||||
enableAllRecipes: async () => {
|
enableAllRecipes: async () => {
|
||||||
try {
|
try {
|
||||||
await fetch(`${API_URL}/recipes/enable-all`, { method: 'POST' });
|
await fetch(`${API_URL}/recipes/enable-all`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ commandId: newCommandId() }),
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error enabling all recipes:', error);
|
console.error('❌ Error enabling all recipes:', error);
|
||||||
}
|
}
|
||||||
@@ -236,7 +253,11 @@ export const useInventoryStore = create((set, get) => ({
|
|||||||
|
|
||||||
disableAllRecipes: async () => {
|
disableAllRecipes: async () => {
|
||||||
try {
|
try {
|
||||||
await fetch(`${API_URL}/recipes/disable-all`, { method: 'POST' });
|
await fetch(`${API_URL}/recipes/disable-all`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ commandId: newCommandId() }),
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Error disabling all recipes:', error);
|
console.error('❌ Error disabling all recipes:', error);
|
||||||
}
|
}
|
||||||
@@ -247,7 +268,7 @@ export const useInventoryStore = create((set, get) => ({
|
|||||||
const response = await fetch(`${API_URL}/craft`, {
|
const response = await fetch(`${API_URL}/craft`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ recipeIdx }),
|
body: JSON.stringify({ recipeIdx, commandId: newCommandId() }),
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -261,7 +282,7 @@ export const useInventoryStore = create((set, get) => ({
|
|||||||
const response = await fetch(`${API_URL}/sort-barrel`, {
|
const response = await fetch(`${API_URL}/sort-barrel`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ barrelName }),
|
body: JSON.stringify({ barrelName, commandId: newCommandId() }),
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user