fix(api): stop routing through a nonexistent /api/gateway rewrite layer
All checks were successful
build-and-release / build (push) Successful in 1m27s
All checks were successful
build-and-release / build (push) Successful in 1m27s
The K8s ingress for this domain routes any /api/* path directly to the Rust gateway service — there is no rewrite/proxy layer in production that collapses /api/gateway/* down to /api/*. That rewrite only exists as a dev-only vite proxy, so lib/api.ts's request()/apiFetch() (used by Save Changes, Submit for Verification, document upload, wallet, jobs, marketplace, portfolio, and more) were 404ing on every call in production with "Route not found in gateway". ProfilePage.tsx and VerificationStatusPage.tsx each had their own local apiFetch with the same assumption, doubly broken (paths already included /api/, prefixed again). All three now hit the already-fully-qualified /api/... path directly, matching how the working signup/login calls have always done it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
3ec5e60d15
commit
0b38bc6ca5
3 changed files with 17 additions and 12 deletions
|
|
@ -29,7 +29,10 @@ import {
|
||||||
type DocField,
|
type DocField,
|
||||||
} from "~/lib/profile-fields-config";
|
} from "~/lib/profile-fields-config";
|
||||||
|
|
||||||
const API = "/api";
|
// The K8s ingress routes /api/* directly to the Rust gateway service in
|
||||||
|
// production — there is no /api/gateway rewrite layer, so paths below are
|
||||||
|
// hit as-is (each apiFetch() call already passes a fully-qualified /api/... path).
|
||||||
|
const API = "";
|
||||||
|
|
||||||
const PORTFOLIO_PREFIX: Record<string, string> = {
|
const PORTFOLIO_PREFIX: Record<string, string> = {
|
||||||
PHOTOGRAPHER: "photographers",
|
PHOTOGRAPHER: "photographers",
|
||||||
|
|
@ -800,7 +803,7 @@ export default function ProfilePage(props: Props) {
|
||||||
: "";
|
: "";
|
||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append("file", file);
|
fd.append("file", file);
|
||||||
const res = await fetch(`${API}/profile/photo`, {
|
const res = await fetch(`${API}/api/profile/photo`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,20 @@ import { ShieldCheck, FileText, Activity } from 'lucide-solid';
|
||||||
import { CARD, BTN_ORANGE, BTN_GHOST } from '~/components/DashboardShell';
|
import { CARD, BTN_ORANGE, BTN_GHOST } from '~/components/DashboardShell';
|
||||||
import { getDocFields } from '~/lib/profile-fields-config';
|
import { getDocFields } from '~/lib/profile-fields-config';
|
||||||
|
|
||||||
const API = '/api/gateway';
|
|
||||||
const NAVY = '#0D0D2A';
|
const NAVY = '#0D0D2A';
|
||||||
const ORANGE = '#FF5E13';
|
const ORANGE = '#FF5E13';
|
||||||
|
|
||||||
type TabKey = 'approval_status' | 'documents' | 'activity';
|
type TabKey = 'approval_status' | 'documents' | 'activity';
|
||||||
|
|
||||||
|
// The K8s ingress routes /api/* directly to the Rust gateway service in
|
||||||
|
// production — there is no /api/gateway rewrite layer, so paths (already
|
||||||
|
// fully-qualified /api/... from callers) are hit as-is.
|
||||||
async function apiFetch(path: string, opts?: RequestInit) {
|
async function apiFetch(path: string, opts?: RequestInit) {
|
||||||
const token =
|
const token =
|
||||||
typeof window !== "undefined"
|
typeof window !== "undefined"
|
||||||
? window.sessionStorage.getItem("nxtgauge_access_token") || ""
|
? window.sessionStorage.getItem("nxtgauge_access_token") || ""
|
||||||
: "";
|
: "";
|
||||||
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path;
|
return fetch(path, {
|
||||||
return fetch(`${API}${cleanPath}`, {
|
|
||||||
...opts,
|
...opts,
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
const API = '/api/gateway';
|
// The K8s ingress routes any /api/* path directly to the Rust gateway service —
|
||||||
|
// there is no /api/gateway indirection or rewrite in production (a dev-only
|
||||||
|
// vite proxy used to do that rewrite, but it doesn't exist in the deployed
|
||||||
|
// build). Callers already pass fully-qualified /api/... paths; hit them as-is.
|
||||||
|
|
||||||
function getAuthHeaders(): Record<string, string> {
|
function getAuthHeaders(): Record<string, string> {
|
||||||
const token = typeof window !== 'undefined'
|
const token = typeof window !== 'undefined'
|
||||||
|
|
@ -12,8 +15,7 @@ function getAuthHeaders(): Record<string, string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function apiFetch(path: string, options?: RequestInit): Promise<any> {
|
export async function apiFetch(path: string, options?: RequestInit): Promise<any> {
|
||||||
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path;
|
const res = await fetch(path, {
|
||||||
const res = await fetch(`${API}${cleanPath}`, {
|
|
||||||
headers: getAuthHeaders(),
|
headers: getAuthHeaders(),
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
...options,
|
...options,
|
||||||
|
|
@ -47,8 +49,7 @@ export async function request<T = any>(
|
||||||
if (options?.body !== undefined) {
|
if (options?.body !== undefined) {
|
||||||
init.body = JSON.stringify(options.body);
|
init.body = JSON.stringify(options.body);
|
||||||
}
|
}
|
||||||
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path;
|
const res = await fetch(path, init);
|
||||||
const res = await fetch(`${API}${cleanPath}`, init);
|
|
||||||
const raw = await res.text();
|
const raw = await res.text();
|
||||||
const data = raw ? JSON.parse(raw) : null;
|
const data = raw ? JSON.parse(raw) : null;
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
|
@ -223,7 +224,7 @@ export async function uploadDocument(rolePrefix: string, file: File, documentTyp
|
||||||
? (sessionStorage.getItem('nxtgauge_access_token') || '')
|
? (sessionStorage.getItem('nxtgauge_access_token') || '')
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
const res = await fetch(`${API}/api/${rolePrefix}/profile/documents`, {
|
const res = await fetch(`/api/${rolePrefix}/profile/documents`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||||
|
|
@ -257,7 +258,7 @@ export async function submitCompanyProfileWithDocuments(
|
||||||
// Append a stable filename so the backend can derive document_type from the stem
|
// Append a stable filename so the backend can derive document_type from the stem
|
||||||
fd.append('documents', file, `${documentType}_${file.name}`);
|
fd.append('documents', file, `${documentType}_${file.name}`);
|
||||||
}
|
}
|
||||||
const res = await fetch(`${API}/api/companies/profile/submit-with-documents`, {
|
const res = await fetch(`/api/companies/profile/submit-with-documents`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue