refactor(backend): resolve legacy Supabase client inside user, profile, and snapshot repositories
Made-with: Cursor
This commit is contained in:
parent
b632a0d946
commit
f0dd2055bf
@ -13,7 +13,6 @@ import { ManualTrader } from './services/ManualTrader.js';
|
||||
import { TradeMonitor } from './services/tradeMonitor.js';
|
||||
import { OrderStatusSyncEvent, OrderStatusSyncService } from './services/OrderStatusSyncService.js';
|
||||
|
||||
import { supabaseService } from './services/SupabaseService.js';
|
||||
import { healthTracker } from './services/healthTracker.js';
|
||||
import { observabilityService } from './services/observabilityService.js';
|
||||
import { reconciliationService } from './services/reconciliationService.js';
|
||||
@ -49,7 +48,7 @@ async function main() {
|
||||
}
|
||||
// --- 0. Load user configuration (Cosmos-first; legacy Supabase optional) ---
|
||||
logger.info('Fetching active trading users...');
|
||||
let users = await listActiveTradingUsers(supabaseService);
|
||||
let users = await listActiveTradingUsers();
|
||||
|
||||
// --- 1. Identify Primary Key (for Data Fetching) ---
|
||||
const isPlaceholder = (val: string) => !val || val === 'your_key' || val === 'your_secret';
|
||||
@ -264,7 +263,7 @@ async function main() {
|
||||
}
|
||||
|
||||
// --- 0. Initialize Signal Subscribers (Users & Profiles) ---
|
||||
const profiles = await listActiveTradeProfiles(supabaseService);
|
||||
const profiles = await listActiveTradeProfiles();
|
||||
|
||||
if (profiles.length > 0) {
|
||||
logger.info(`👥 Initializing Execution Managers for ${profiles.length} Trade Profiles...`);
|
||||
@ -396,8 +395,8 @@ async function main() {
|
||||
// --- PROFILE HOT-RELOAD: Sync new/updated/deactivated profiles periodically ---
|
||||
setInterval(async () => {
|
||||
try {
|
||||
users = await listActiveTradingUsers(supabaseService);
|
||||
const latestProfiles = await listActiveTradeProfiles(supabaseService);
|
||||
users = await listActiveTradingUsers();
|
||||
const latestProfiles = await listActiveTradeProfiles();
|
||||
const currentIds = new Set(userContexts.map(c => c.profileId));
|
||||
const latestIds = new Set(latestProfiles.map((p: any) => p.id));
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ export class CapitalLedger {
|
||||
|
||||
private async ensureLedger(profileId: string, allocatedCapital?: number): Promise<CapitalLedgerRecord | null> {
|
||||
try {
|
||||
const profileCapital = await getTradeProfileCapital(profileId, supabaseService);
|
||||
const profileCapital = await getTradeProfileCapital(profileId);
|
||||
const allocation = toNumeric(allocatedCapital ?? profileCapital?.allocatedCapital ?? config.TOTAL_CAPITAL);
|
||||
const existing = await getCapitalLedger(profileId, supabaseService);
|
||||
const nextRecord: CapitalLedgerRecord = {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import type { TradeExecutor } from './TradeExecutor.js';
|
||||
import { SignalDirection } from '../strategies/rules/types.js';
|
||||
import logger from '../utils/logger.js';
|
||||
import { supabaseService } from './SupabaseService.js';
|
||||
import { config } from '../config/index.js';
|
||||
import { getTradeProfileCapital } from './profileRepository.js';
|
||||
|
||||
@ -34,7 +33,7 @@ export class ManualTrader {
|
||||
return Number(config.TOTAL_CAPITAL || 0);
|
||||
}
|
||||
|
||||
const profileCapital = await getTradeProfileCapital(profileId, supabaseService);
|
||||
const profileCapital = await getTradeProfileCapital(profileId);
|
||||
if (profileCapital?.allocatedCapital && profileCapital.allocatedCapital > 0) {
|
||||
return profileCapital.allocatedCapital;
|
||||
}
|
||||
|
||||
@ -1113,7 +1113,7 @@ export class ApiServer {
|
||||
|
||||
private async resolveSnapshotOwnerId(): Promise<string | null> {
|
||||
if (this.snapshotOwnerId) return this.snapshotOwnerId;
|
||||
const owner = await resolveSnapshotOwnerIdFromRepository(supabaseService);
|
||||
const owner = await resolveSnapshotOwnerIdFromRepository();
|
||||
this.snapshotOwnerId = owner;
|
||||
return owner;
|
||||
}
|
||||
@ -1124,7 +1124,7 @@ export class ApiServer {
|
||||
if (!ownerId) {
|
||||
logger.warn('[API] Snapshot owner not resolved; skipping snapshot restore.');
|
||||
} else {
|
||||
const snapshot = await loadLatestBotStateSnapshotFromRepository(ownerId, supabaseService);
|
||||
const snapshot = await loadLatestBotStateSnapshotFromRepository(ownerId);
|
||||
if (snapshot && snapshot.state) {
|
||||
const restoredState = snapshot.state as Partial<BotState>;
|
||||
this.state = {
|
||||
@ -1189,7 +1189,7 @@ export class ApiServer {
|
||||
try {
|
||||
const ownerId = await this.resolveSnapshotOwnerId();
|
||||
if (!ownerId) return;
|
||||
await saveBotStateSnapshotFromRepository(ownerId, this.getPersistableState(), supabaseService);
|
||||
await saveBotStateSnapshotFromRepository(ownerId, this.getPersistableState());
|
||||
this.lastSnapshotWriteAt = Date.now();
|
||||
logger.info(`[API] Persisted snapshot for ${ownerId}. Interval: ${Math.round(elapsed / 1000)}s`);
|
||||
} catch (error: any) {
|
||||
@ -1311,8 +1311,8 @@ export class ApiServer {
|
||||
);
|
||||
|
||||
const profileRows = isAdmin
|
||||
? await listAllTradeProfiles(supabaseService)
|
||||
: await listTradeProfilesForUser(authUserId, supabaseService);
|
||||
? await listAllTradeProfiles()
|
||||
: await listTradeProfilesForUser(authUserId);
|
||||
|
||||
if (requestedProfileId && !profileRows.some((row) => row.id === requestedProfileId)) {
|
||||
res.status(403).json({ success: false, error: 'Forbidden: profile does not belong to scoped user context' });
|
||||
@ -1672,7 +1672,7 @@ export class ApiServer {
|
||||
first_name: displayNameParts[0] || '',
|
||||
last_name: displayNameParts.slice(1).join(' '),
|
||||
trade_enable: true,
|
||||
}, supabaseService);
|
||||
});
|
||||
|
||||
res.json({ profile });
|
||||
});
|
||||
@ -1693,7 +1693,7 @@ export class ApiServer {
|
||||
first_name: displayNameParts[0] || '',
|
||||
last_name: displayNameParts.slice(1).join(' '),
|
||||
trade_enable: true,
|
||||
}, supabaseService);
|
||||
});
|
||||
res.json({ profile });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ error: `Failed to update profile: ${error.message}` });
|
||||
@ -1715,15 +1715,15 @@ export class ApiServer {
|
||||
|
||||
let profiles;
|
||||
if (ensureDefault && !wantsAll) {
|
||||
profiles = await ensureDefaultTradeProfileForUser(authUserId, supabaseService);
|
||||
profiles = await ensureDefaultTradeProfileForUser(authUserId);
|
||||
} else if (wantsAll) {
|
||||
if (!isAdmin) {
|
||||
res.status(403).json({ error: 'Forbidden: Admin role required' });
|
||||
return;
|
||||
}
|
||||
profiles = await listAllTradeProfiles(supabaseService);
|
||||
profiles = await listAllTradeProfiles();
|
||||
} else {
|
||||
profiles = await listTradeProfilesForUser(authUserId, supabaseService);
|
||||
profiles = await listTradeProfilesForUser(authUserId);
|
||||
}
|
||||
res.json({ profiles });
|
||||
} catch (error: any) {
|
||||
@ -1743,7 +1743,7 @@ export class ApiServer {
|
||||
const isAdmin = await isTradingAdmin(authUserId, authReq.authRole);
|
||||
const requestedUserId = String(req.body?.user_id || '').trim();
|
||||
const targetUserId = isAdmin && requestedUserId ? requestedUserId : authUserId;
|
||||
const profile = await saveTradeProfileForUser(req.body || {}, targetUserId, supabaseService);
|
||||
const profile = await saveTradeProfileForUser(req.body || {}, targetUserId);
|
||||
res.status(201).json({ profile });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ error: `Failed to save profile: ${error.message}` });
|
||||
@ -1762,8 +1762,8 @@ export class ApiServer {
|
||||
const profileId = String(req.params.id || '').trim();
|
||||
const isAdmin = await isTradingAdmin(authUserId, authReq.authRole);
|
||||
const existingProfiles = isAdmin
|
||||
? await listAllTradeProfiles(supabaseService)
|
||||
: await listTradeProfilesForUser(authUserId, supabaseService);
|
||||
? await listAllTradeProfiles()
|
||||
: await listTradeProfilesForUser(authUserId);
|
||||
const existing = existingProfiles.find((profile) => profile.id === profileId);
|
||||
if (!existing) {
|
||||
res.status(404).json({ error: 'Profile not found' });
|
||||
@ -1774,7 +1774,7 @@ export class ApiServer {
|
||||
...existing,
|
||||
...(req.body || {}),
|
||||
id: profileId,
|
||||
}, existing.user_id, supabaseService);
|
||||
}, existing.user_id);
|
||||
res.json({ profile });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ error: `Failed to update profile: ${error.message}` });
|
||||
@ -1793,8 +1793,8 @@ export class ApiServer {
|
||||
const profileId = String(req.params.id || '').trim();
|
||||
const isAdmin = await isTradingAdmin(authUserId, authReq.authRole);
|
||||
const existingProfiles = isAdmin
|
||||
? await listAllTradeProfiles(supabaseService)
|
||||
: await listTradeProfilesForUser(authUserId, supabaseService);
|
||||
? await listAllTradeProfiles()
|
||||
: await listTradeProfilesForUser(authUserId);
|
||||
const existing = existingProfiles
|
||||
.find((profile) => profile.id === profileId);
|
||||
if (!existing) {
|
||||
@ -1805,7 +1805,7 @@ export class ApiServer {
|
||||
const profile = await saveTradeProfileForUser({
|
||||
...existing,
|
||||
is_active: Boolean(req.body?.is_active),
|
||||
}, existing.user_id, supabaseService);
|
||||
}, existing.user_id);
|
||||
res.json({ profile });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ error: `Failed to update profile state: ${error.message}` });
|
||||
@ -1824,15 +1824,15 @@ export class ApiServer {
|
||||
const profileId = String(req.params.id || '').trim();
|
||||
const isAdmin = await isTradingAdmin(authUserId, authReq.authRole);
|
||||
const existingProfiles = isAdmin
|
||||
? await listAllTradeProfiles(supabaseService)
|
||||
: await listTradeProfilesForUser(authUserId, supabaseService);
|
||||
? await listAllTradeProfiles()
|
||||
: await listTradeProfilesForUser(authUserId);
|
||||
const existing = existingProfiles.find((profile) => profile.id === profileId);
|
||||
if (!existing) {
|
||||
res.status(404).json({ error: 'Profile not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
await deleteTradeProfileForUser(profileId, existing.user_id, supabaseService);
|
||||
await deleteTradeProfileForUser(profileId, existing.user_id);
|
||||
res.json({ success: true });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ error: `Failed to delete profile: ${error.message}` });
|
||||
@ -1879,8 +1879,8 @@ export class ApiServer {
|
||||
limit: orderLimit
|
||||
}),
|
||||
wantsAll
|
||||
? listAllTradeProfiles(supabaseService)
|
||||
: listTradeProfilesForUser(authUserId, supabaseService)
|
||||
? listAllTradeProfiles()
|
||||
: listTradeProfilesForUser(authUserId)
|
||||
]);
|
||||
|
||||
res.json({
|
||||
@ -2045,7 +2045,7 @@ export class ApiServer {
|
||||
const profileId = String(body.profileId || '').trim();
|
||||
let profileSettings: any = undefined;
|
||||
if (profileId) {
|
||||
profileSettings = await getTradeProfileForUser(profileId, authUserId, supabaseService);
|
||||
profileSettings = await getTradeProfileForUser(profileId, authUserId);
|
||||
if (!profileSettings) {
|
||||
res.status(404).json({ success: false, error: 'Backtest profile not found for current user' });
|
||||
return;
|
||||
|
||||
@ -2,9 +2,7 @@ import { getContainer } from '@bytelyst/cosmos';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { config } from '../config/index.js';
|
||||
import logger from '../utils/logger.js';
|
||||
import type { supabaseService } from './SupabaseService.js';
|
||||
|
||||
type LegacySupabaseService = typeof supabaseService;
|
||||
import { supabaseService } from './SupabaseService.js';
|
||||
|
||||
export interface TradingUserProfile {
|
||||
user_id: string;
|
||||
@ -63,6 +61,10 @@ function isCosmosConfigured(): boolean {
|
||||
return Boolean(config.COSMOS_ENDPOINT && config.COSMOS_KEY);
|
||||
}
|
||||
|
||||
function getLegacyClient() {
|
||||
return supabaseService.getClient();
|
||||
}
|
||||
|
||||
function normalizeProfile(row: Partial<TradeProfileRecord> | null | undefined): TradeProfileRecord | null {
|
||||
const id = String(row?.id || '').trim();
|
||||
const userId = String(row?.user_id || '').trim();
|
||||
@ -223,8 +225,8 @@ async function listAllProfilesFromCosmos(): Promise<TradeProfileRecord[]> {
|
||||
.filter((profile): profile is TradeProfileRecord => Boolean(profile));
|
||||
}
|
||||
|
||||
async function listProfilesFromSupabase(userId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
|
||||
const client = legacyService?.getClient?.();
|
||||
async function listProfilesFromSupabase(userId: string): Promise<TradeProfileRecord[]> {
|
||||
const client = getLegacyClient();
|
||||
if (!client) {
|
||||
return [];
|
||||
}
|
||||
@ -265,8 +267,8 @@ async function seedProfilesToCosmos(profiles: TradeProfileRecord[]): Promise<Tra
|
||||
return profiles;
|
||||
}
|
||||
|
||||
async function listAllProfilesFromSupabase(legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
|
||||
const client = legacyService?.getClient?.();
|
||||
async function listAllProfilesFromSupabase(): Promise<TradeProfileRecord[]> {
|
||||
const client = getLegacyClient();
|
||||
if (!client) {
|
||||
return [];
|
||||
}
|
||||
@ -317,8 +319,8 @@ async function getProfileFromCosmos(profileId: string): Promise<TradeProfileReco
|
||||
});
|
||||
}
|
||||
|
||||
async function getProfileFromSupabase(profileId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord | null> {
|
||||
const client = legacyService?.getClient?.();
|
||||
async function getProfileFromSupabase(profileId: string): Promise<TradeProfileRecord | null> {
|
||||
const client = getLegacyClient();
|
||||
if (!client || !profileId) {
|
||||
return null;
|
||||
}
|
||||
@ -341,8 +343,8 @@ async function getProfileFromSupabase(profileId: string, legacyService?: LegacyS
|
||||
}
|
||||
}
|
||||
|
||||
async function mirrorProfileToSupabase(profile: TradeProfileRecord, legacyService?: LegacySupabaseService): Promise<void> {
|
||||
const client = legacyService?.getClient?.();
|
||||
async function mirrorProfileToSupabase(profile: TradeProfileRecord): Promise<void> {
|
||||
const client = getLegacyClient();
|
||||
if (!client) return;
|
||||
|
||||
try {
|
||||
@ -362,8 +364,8 @@ async function mirrorProfileToSupabase(profile: TradeProfileRecord, legacyServic
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteProfileFromSupabase(profileId: string, userId: string, legacyService?: LegacySupabaseService): Promise<void> {
|
||||
const client = legacyService?.getClient?.();
|
||||
async function deleteProfileFromSupabase(profileId: string, userId: string): Promise<void> {
|
||||
const client = getLegacyClient();
|
||||
if (!client) return;
|
||||
|
||||
try {
|
||||
@ -381,9 +383,9 @@ async function deleteProfileFromSupabase(profileId: string, userId: string, lega
|
||||
}
|
||||
}
|
||||
|
||||
export async function listTradeProfilesForUser(userId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
|
||||
export async function listTradeProfilesForUser(userId: string): Promise<TradeProfileRecord[]> {
|
||||
if (!isCosmosConfigured()) {
|
||||
return listProfilesFromSupabase(userId, legacyService);
|
||||
return listProfilesFromSupabase(userId);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -391,7 +393,7 @@ export async function listTradeProfilesForUser(userId: string, legacyService?: L
|
||||
if (cosmosProfiles.length > 0) {
|
||||
return cosmosProfiles;
|
||||
}
|
||||
const seededProfiles = await seedProfilesToCosmos(await listProfilesFromSupabase(userId, legacyService));
|
||||
const seededProfiles = await seedProfilesToCosmos(await listProfilesFromSupabase(userId));
|
||||
if (seededProfiles.length > 0) {
|
||||
logger.info(`[Profiles] Seeded ${seededProfiles.length} user profiles from legacy store into Cosmos for user ${userId}.`);
|
||||
}
|
||||
@ -402,9 +404,9 @@ export async function listTradeProfilesForUser(userId: string, legacyService?: L
|
||||
}
|
||||
}
|
||||
|
||||
export async function listAllTradeProfiles(legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
|
||||
export async function listAllTradeProfiles(): Promise<TradeProfileRecord[]> {
|
||||
if (!isCosmosConfigured()) {
|
||||
return listAllProfilesFromSupabase(legacyService);
|
||||
return listAllProfilesFromSupabase();
|
||||
}
|
||||
|
||||
try {
|
||||
@ -412,7 +414,7 @@ export async function listAllTradeProfiles(legacyService?: LegacySupabaseService
|
||||
if (cosmosProfiles.length > 0) {
|
||||
return cosmosProfiles;
|
||||
}
|
||||
const seededProfiles = await seedProfilesToCosmos(await listAllProfilesFromSupabase(legacyService));
|
||||
const seededProfiles = await seedProfilesToCosmos(await listAllProfilesFromSupabase());
|
||||
if (seededProfiles.length > 0) {
|
||||
logger.info(`[Profiles] Seeded ${seededProfiles.length} profiles from legacy store into Cosmos.`);
|
||||
}
|
||||
@ -423,19 +425,19 @@ export async function listAllTradeProfiles(legacyService?: LegacySupabaseService
|
||||
}
|
||||
}
|
||||
|
||||
export async function listActiveTradeProfiles(legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
|
||||
const profiles = await listAllTradeProfiles(legacyService);
|
||||
export async function listActiveTradeProfiles(): Promise<TradeProfileRecord[]> {
|
||||
const profiles = await listAllTradeProfiles();
|
||||
return profiles.filter((profile) => Boolean(profile.is_active));
|
||||
}
|
||||
|
||||
export async function getTradeProfileById(profileId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord | null> {
|
||||
export async function getTradeProfileById(profileId: string): Promise<TradeProfileRecord | null> {
|
||||
const normalizedId = String(profileId || '').trim();
|
||||
if (!normalizedId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isCosmosConfigured()) {
|
||||
return getProfileFromSupabase(normalizedId, legacyService);
|
||||
return getProfileFromSupabase(normalizedId);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -443,7 +445,7 @@ export async function getTradeProfileById(profileId: string, legacyService?: Leg
|
||||
if (cosmosProfile) {
|
||||
return cosmosProfile;
|
||||
}
|
||||
const legacyProfile = await getProfileFromSupabase(normalizedId, legacyService);
|
||||
const legacyProfile = await getProfileFromSupabase(normalizedId);
|
||||
if (!legacyProfile) {
|
||||
return null;
|
||||
}
|
||||
@ -456,8 +458,8 @@ export async function getTradeProfileById(profileId: string, legacyService?: Leg
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTradeProfileCapital(profileId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileCapitalSummary | null> {
|
||||
const profile = await getTradeProfileById(profileId, legacyService);
|
||||
export async function getTradeProfileCapital(profileId: string): Promise<TradeProfileCapitalSummary | null> {
|
||||
const profile = await getTradeProfileById(profileId);
|
||||
if (!profile) {
|
||||
return null;
|
||||
}
|
||||
@ -469,28 +471,27 @@ export async function getTradeProfileCapital(profileId: string, legacyService?:
|
||||
};
|
||||
}
|
||||
|
||||
export async function getTradeProfileForUser(profileId: string, userId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord | null> {
|
||||
const profile = await getTradeProfileById(profileId, legacyService);
|
||||
export async function getTradeProfileForUser(profileId: string, userId: string): Promise<TradeProfileRecord | null> {
|
||||
const profile = await getTradeProfileById(profileId);
|
||||
if (!profile || String(profile.user_id || '').trim() !== String(userId || '').trim()) {
|
||||
return null;
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
export async function ensureDefaultTradeProfileForUser(userId: string, legacyService?: LegacySupabaseService): Promise<TradeProfileRecord[]> {
|
||||
const profiles = await listTradeProfilesForUser(userId, legacyService);
|
||||
export async function ensureDefaultTradeProfileForUser(userId: string): Promise<TradeProfileRecord[]> {
|
||||
const profiles = await listTradeProfilesForUser(userId);
|
||||
if (profiles.length > 0) {
|
||||
return profiles;
|
||||
}
|
||||
|
||||
const created = await saveTradeProfileForUser(buildDefaultTradeProfile(userId), userId, legacyService);
|
||||
const created = await saveTradeProfileForUser(buildDefaultTradeProfile(userId), userId);
|
||||
return [created];
|
||||
}
|
||||
|
||||
export async function saveTradeProfileForUser(
|
||||
input: Partial<TradeProfileRecord>,
|
||||
userId: string,
|
||||
legacyService?: LegacySupabaseService
|
||||
userId: string
|
||||
): Promise<TradeProfileRecord> {
|
||||
const now = new Date().toISOString();
|
||||
const normalized = normalizeProfile({
|
||||
@ -520,14 +521,13 @@ export async function saveTradeProfileForUser(
|
||||
}
|
||||
}
|
||||
|
||||
await mirrorProfileToSupabase(normalized, legacyService);
|
||||
await mirrorProfileToSupabase(normalized);
|
||||
return normalized;
|
||||
}
|
||||
|
||||
export async function deleteTradeProfileForUser(
|
||||
profileId: string,
|
||||
userId: string,
|
||||
legacyService?: LegacySupabaseService
|
||||
userId: string
|
||||
): Promise<void> {
|
||||
if (!profileId || !userId) {
|
||||
return;
|
||||
@ -542,13 +542,12 @@ export async function deleteTradeProfileForUser(
|
||||
}
|
||||
}
|
||||
|
||||
await deleteProfileFromSupabase(profileId, userId, legacyService);
|
||||
await deleteProfileFromSupabase(profileId, userId);
|
||||
}
|
||||
|
||||
export async function getCurrentUserProfile(
|
||||
userId: string,
|
||||
fallback: Partial<TradingUserProfile> = {},
|
||||
legacyService?: LegacySupabaseService
|
||||
fallback: Partial<TradingUserProfile> = {}
|
||||
): Promise<TradingUserProfile> {
|
||||
if (isCosmosConfigured()) {
|
||||
try {
|
||||
@ -561,7 +560,7 @@ export async function getCurrentUserProfile(
|
||||
}
|
||||
}
|
||||
|
||||
const client = legacyService?.getClient?.();
|
||||
const client = getLegacyClient();
|
||||
if (client) {
|
||||
try {
|
||||
const { data, error } = await client
|
||||
@ -614,10 +613,9 @@ export async function getCurrentUserProfile(
|
||||
export async function saveCurrentUserProfile(
|
||||
userId: string,
|
||||
input: Partial<TradingUserProfile>,
|
||||
fallback: Partial<TradingUserProfile> = {},
|
||||
legacyService?: LegacySupabaseService
|
||||
fallback: Partial<TradingUserProfile> = {}
|
||||
): Promise<TradingUserProfile> {
|
||||
const existing = await getCurrentUserProfile(userId, fallback, legacyService);
|
||||
const existing = await getCurrentUserProfile(userId, fallback);
|
||||
const merged: TradingUserProfile = {
|
||||
...existing,
|
||||
...input,
|
||||
@ -638,7 +636,7 @@ export async function saveCurrentUserProfile(
|
||||
logger.warn(`[Profiles] Cosmos user profile save failed: ${error instanceof Error ? error.message : 'unknown error'}`);
|
||||
}
|
||||
|
||||
const client = legacyService?.getClient?.();
|
||||
const client = getLegacyClient();
|
||||
if (client) {
|
||||
try {
|
||||
const { error } = await client
|
||||
|
||||
@ -3,7 +3,6 @@ import { config } from '../config/index.js';
|
||||
import logger from '../utils/logger.js';
|
||||
import { healthTracker } from './healthTracker.js';
|
||||
import { observabilityService } from './observabilityService.js';
|
||||
import { supabaseService } from './SupabaseService.js';
|
||||
import { getTradeProfileCapital } from './profileRepository.js';
|
||||
import type { TradeExecutor } from './TradeExecutor.js';
|
||||
import { buildAlpacaSubTag } from '../utils/alpacaSubTag.js';
|
||||
@ -277,7 +276,7 @@ export class ReconciliationParityHeartbeatService {
|
||||
const throttleMs = Math.max(0, toNumber(config.RECON_INTEGRITY_WATCHDOG_THROTTLE_MS || 600_000));
|
||||
const requireSubTagAttribution = Boolean(config.RECON_POSITION_PARITY_REQUIRE_SUBTAG_ATTRIBUTION);
|
||||
const allowLegacyEntryAttribution = Boolean(config.RECON_POSITION_PARITY_ALLOW_LEGACY_ENTRY_ATTRIBUTION);
|
||||
const profileCapital = await getTradeProfileCapital(profileId, supabaseService);
|
||||
const profileCapital = await getTradeProfileCapital(profileId);
|
||||
const allocatedCapitalUsd = Math.max(0, toNumber(profileCapital?.allocatedCapital));
|
||||
|
||||
let mismatchTrades = 0;
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
import { getContainer } from '@bytelyst/cosmos';
|
||||
import { config } from '../config/index.js';
|
||||
import logger from '../utils/logger.js';
|
||||
import type { supabaseService } from './SupabaseService.js';
|
||||
import { supabaseService } from './SupabaseService.js';
|
||||
import { listActiveTradingUsers } from './userRepository.js';
|
||||
|
||||
type LegacySupabaseService = typeof supabaseService;
|
||||
|
||||
const CONTAINER_NAME = 'bot_state_snapshots';
|
||||
|
||||
interface BotStateSnapshotDocument {
|
||||
@ -28,13 +26,13 @@ function buildSnapshotId(ownerId: string): string {
|
||||
return `${config.PRODUCT_ID}:${ownerId}`;
|
||||
}
|
||||
|
||||
export async function resolveSnapshotOwnerId(legacyService?: LegacySupabaseService): Promise<string | null> {
|
||||
export async function resolveSnapshotOwnerId(): Promise<string | null> {
|
||||
const configured = String(config.SNAPSHOT_USER_ID || '').trim().toLowerCase();
|
||||
if (isUuid(configured)) {
|
||||
return configured;
|
||||
}
|
||||
|
||||
const users = await listActiveTradingUsers(legacyService);
|
||||
const users = await listActiveTradingUsers();
|
||||
const firstUserId = String(users[0]?.user_id || '').trim().toLowerCase();
|
||||
if (isUuid(firstUserId)) {
|
||||
return firstUserId;
|
||||
@ -44,12 +42,11 @@ export async function resolveSnapshotOwnerId(legacyService?: LegacySupabaseServi
|
||||
}
|
||||
|
||||
export async function loadLatestBotStateSnapshot(
|
||||
ownerId: string,
|
||||
legacyService?: LegacySupabaseService
|
||||
ownerId: string
|
||||
): Promise<{ state: unknown } | null> {
|
||||
if (!ownerId) return null;
|
||||
|
||||
const loadLegacySnapshot = async () => legacyService?.loadLatestBotStateSnapshot(ownerId) ?? null;
|
||||
const loadLegacySnapshot = async () => supabaseService.loadLatestBotStateSnapshot(ownerId);
|
||||
|
||||
if (!isCosmosConfigured()) {
|
||||
return loadLegacySnapshot();
|
||||
@ -90,8 +87,7 @@ export async function loadLatestBotStateSnapshot(
|
||||
|
||||
export async function saveBotStateSnapshot(
|
||||
ownerId: string,
|
||||
state: unknown,
|
||||
legacyService?: LegacySupabaseService
|
||||
state: unknown
|
||||
): Promise<void> {
|
||||
if (!ownerId) return;
|
||||
|
||||
@ -112,5 +108,5 @@ export async function saveBotStateSnapshot(
|
||||
}
|
||||
}
|
||||
|
||||
await legacyService?.saveBotStateSnapshot(ownerId, state);
|
||||
await supabaseService.saveBotStateSnapshot(ownerId, state);
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { getContainer } from '@bytelyst/cosmos';
|
||||
import { config } from '../config/index.js';
|
||||
import logger from '../utils/logger.js';
|
||||
import type { UserConfig, supabaseService } from './SupabaseService.js';
|
||||
import type { UserConfig } from './SupabaseService.js';
|
||||
import { supabaseService } from './SupabaseService.js';
|
||||
|
||||
type LegacySupabaseService = typeof supabaseService;
|
||||
const USER_PROFILE_CONTAINER = 'trading_users';
|
||||
|
||||
interface TradingUserDocument extends UserConfig {
|
||||
@ -39,7 +39,7 @@ function normalizeUser(row: Partial<UserConfig> | null | undefined): UserConfig
|
||||
};
|
||||
}
|
||||
|
||||
export async function listActiveTradingUsers(legacyService?: LegacySupabaseService): Promise<UserConfig[]> {
|
||||
export async function listActiveTradingUsers(): Promise<UserConfig[]> {
|
||||
if (isCosmosConfigured()) {
|
||||
try {
|
||||
const container = getContainer(USER_PROFILE_CONTAINER);
|
||||
@ -63,7 +63,7 @@ export async function listActiveTradingUsers(legacyService?: LegacySupabaseServi
|
||||
}
|
||||
}
|
||||
|
||||
const client = legacyService?.getClient?.();
|
||||
const client = supabaseService.getClient();
|
||||
if (!client) {
|
||||
return [];
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user