fix: credit tracking, voice clone TTL, avatar upload ui, asset serving fallback, OAuth encryption, free plan video renders, backlink outreach sprint
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { aiApiClient, getAuthTokenGetter } from '../api/client';
|
||||
import { getApiBaseUrl } from '../utils/apiUrl';
|
||||
|
||||
export interface ChartGenerateRequest {
|
||||
chart_data?: Record<string, any>;
|
||||
@@ -23,11 +24,7 @@ class ChartApiService {
|
||||
private baseUrl: string;
|
||||
|
||||
constructor() {
|
||||
const url = process.env.REACT_APP_API_URL;
|
||||
if (process.env.NODE_ENV === 'production' && !url) {
|
||||
throw new Error('REACT_APP_API_URL environment variable is required for production');
|
||||
}
|
||||
this.baseUrl = url || 'http://localhost:8000';
|
||||
this.baseUrl = getApiBaseUrl();
|
||||
}
|
||||
|
||||
async generateChartExplicit(params: {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
import { longRunningApiClient } from '../api/client';
|
||||
import { getApiBaseUrl } from '../utils/apiUrl';
|
||||
|
||||
export interface SourceDocument {
|
||||
title: string;
|
||||
@@ -79,13 +80,6 @@ class HallucinationDetectorService {
|
||||
private baseUrl: string;
|
||||
|
||||
constructor() {
|
||||
const getApiBaseUrl = () => {
|
||||
const url = process.env.REACT_APP_API_URL;
|
||||
if (process.env.NODE_ENV === 'production' && !url) {
|
||||
throw new Error('REACT_APP_API_URL environment variable is required for production');
|
||||
}
|
||||
return url || 'http://localhost:8000';
|
||||
};
|
||||
this.baseUrl = getApiBaseUrl();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { aiApiClient } from '../api/client';
|
||||
import { getApiBaseUrl } from '../utils/apiUrl';
|
||||
|
||||
export interface LinkSearchRequest {
|
||||
query: string;
|
||||
@@ -37,11 +38,7 @@ class LinkApiService {
|
||||
private baseUrl: string;
|
||||
|
||||
constructor() {
|
||||
const url = process.env.REACT_APP_API_URL;
|
||||
if (process.env.NODE_ENV === 'production' && !url) {
|
||||
throw new Error('REACT_APP_API_URL environment variable is required for production');
|
||||
}
|
||||
this.baseUrl = url || 'http://localhost:8000';
|
||||
this.baseUrl = getApiBaseUrl();
|
||||
}
|
||||
|
||||
async searchLinks(params: LinkSearchRequest): Promise<LinkSearchResponse> {
|
||||
|
||||
@@ -39,14 +39,14 @@ const DEFAULT_KNOBS: Knobs = {
|
||||
};
|
||||
|
||||
const VOICE_CLONE_STORAGE_KEY = "alwrity_voice_clone_info";
|
||||
const VOICE_CLONE_CACHE_TTL = 30 * 60 * 1000; // 30 minutes
|
||||
const VOICE_CLONE_CACHE_TTL = 2 * 60 * 60 * 1000; // 2 hours (WaveSpeed IDs last longer than documented 30 min)
|
||||
|
||||
function _readVoiceCloneCache() {
|
||||
try {
|
||||
const raw = localStorage.getItem(VOICE_CLONE_STORAGE_KEY);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw);
|
||||
if (parsed && typeof parsed.timestamp === "number" && Date.now() - parsed.timestamp < VOICE_CLONE_CACHE_TTL) {
|
||||
if (parsed && typeof parsed.timestamp === "number") {
|
||||
return parsed;
|
||||
}
|
||||
} catch {
|
||||
@@ -78,10 +78,14 @@ function _clearVoiceCloneCache() {
|
||||
|
||||
/**
|
||||
* Get cached voice clone info from localStorage (survives page refresh).
|
||||
* Returns null if expired (>30 min) or not set.
|
||||
* Returns null if not set. Includes `stale` flag if older than 2 hours
|
||||
* so consumers can proactively re-clone before the API rejects the ID.
|
||||
*/
|
||||
export function getCachedVoiceCloneInfo() {
|
||||
return _readVoiceCloneCache();
|
||||
export function getCachedVoiceCloneInfo(): (ReturnType<typeof _readVoiceCloneCache> & { stale?: boolean }) | null {
|
||||
const cached = _readVoiceCloneCache();
|
||||
if (!cached) return null;
|
||||
const stale = typeof cached.timestamp === "number" && Date.now() - cached.timestamp > VOICE_CLONE_CACHE_TTL;
|
||||
return { ...cached, stale };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,15 +11,7 @@ import {
|
||||
CopilotActionResponse,
|
||||
CopilotSuggestion
|
||||
} from '../types/seoCopilotTypes';
|
||||
|
||||
// API URL - require REACT_APP_API_URL in production
|
||||
const getApiBaseUrl = () => {
|
||||
const url = process.env.REACT_APP_API_URL;
|
||||
if (process.env.NODE_ENV === 'production' && !url) {
|
||||
throw new Error('REACT_APP_API_URL environment variable is required for production');
|
||||
}
|
||||
return url || 'http://localhost:8000';
|
||||
};
|
||||
import { getApiBaseUrl } from '../utils/apiUrl';
|
||||
|
||||
const API_BASE_URL = getApiBaseUrl();
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { getApiBaseUrl } from '../utils/apiUrl';
|
||||
|
||||
export interface WASource {
|
||||
title: string;
|
||||
url: string;
|
||||
@@ -22,13 +24,6 @@ class WritingAssistantService {
|
||||
private baseUrl: string;
|
||||
private authTokenGetter: (() => Promise<string | null>) | null = null;
|
||||
constructor() {
|
||||
const getApiBaseUrl = () => {
|
||||
const url = process.env.REACT_APP_API_URL;
|
||||
if (process.env.NODE_ENV === 'production' && !url) {
|
||||
throw new Error('REACT_APP_API_URL environment variable is required for production');
|
||||
}
|
||||
return url || 'http://localhost:8000';
|
||||
};
|
||||
this.baseUrl = getApiBaseUrl();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user