- Add /trading and /admin named Socket.IO namespaces; root namespace kept for backward compat; admin namespace rejects non-admins at connect time - Wire auditRepository.ts: persist TradeAuditEvent to Cosmos audit-events container (best-effort); expose GET /api/admin/audit for admin queries - Add tradingTelemetry singleton (Node.js Map-based storage adapter); init and fatal-error tracking wired in index.ts main() - Add TAB_MARKETPLACE_ENABLED / TAB_MEMBERSHIP_ENABLED config flags; expose tabs.* shape in GET /api/feature-flags response - Fix SupabaseService URL validation (regex check before createClient) - Wire check:api-contract and check:audit-repository into npm run test - Switch @bytelyst/* deps to file:../vendor/* references Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
97 lines
3.1 KiB
TypeScript
97 lines
3.1 KiB
TypeScript
/**
|
|
* Backend telemetry singleton — wraps @bytelyst/telemetry-client for Node.js.
|
|
*
|
|
* Uses a Map-based storage adapter in place of localStorage (browser/RN default).
|
|
* All tracking calls are fire-and-forget; this module never throws.
|
|
*
|
|
* Initialise once in bootstrap.ts after secrets are resolved:
|
|
* import { tradingTelemetry } from './services/tradingTelemetry.js';
|
|
* tradingTelemetry.init();
|
|
*/
|
|
|
|
import { createTelemetryClient } from '@bytelyst/telemetry-client';
|
|
import type { TelemetryClient, TelemetryStorage } from '@bytelyst/telemetry-client';
|
|
import { config } from '../config/index.js';
|
|
import { productConfig } from '../../../shared/product.js';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Node.js storage adapter — Map replaces localStorage
|
|
// ---------------------------------------------------------------------------
|
|
const nodeStorage: TelemetryStorage = (() => {
|
|
const store = new Map<string, string>();
|
|
return {
|
|
getItem: (key: string) => store.get(key) ?? null,
|
|
setItem: (key: string, value: string) => { store.set(key, value); },
|
|
};
|
|
})();
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Singleton client
|
|
// ---------------------------------------------------------------------------
|
|
const client: TelemetryClient = createTelemetryClient({
|
|
productId: productConfig.productId,
|
|
baseUrl: config.PLATFORM_API_URL,
|
|
platform: 'backend',
|
|
channel: 'invttrdg_backend',
|
|
transport: 'fetch',
|
|
appVersion: productConfig.version,
|
|
releaseChannel: process.env.NODE_ENV === 'production' ? 'production' : 'dev',
|
|
osFamily: 'node',
|
|
osVersion: process.version,
|
|
storage: nodeStorage,
|
|
// Flush every 60s — matches the trading loop polling interval
|
|
flushIntervalMs: 60_000,
|
|
maxQueue: 100,
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Public API
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/** Initialise telemetry and start periodic flushing. Call once at startup. */
|
|
function init(): void {
|
|
try {
|
|
client.init();
|
|
} catch {
|
|
// Non-fatal — telemetry must not prevent trading from starting
|
|
}
|
|
}
|
|
|
|
/** Gracefully flush remaining events and stop the flush timer. */
|
|
async function shutdown(): Promise<void> {
|
|
try {
|
|
client.shutdown();
|
|
} catch {
|
|
// Ignore — we're shutting down anyway
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Track a backend telemetry event. Never throws.
|
|
*
|
|
* @param eventType Severity/class: 'info' | 'error' | 'lifecycle' | 'perf'
|
|
* @param module Source module label, e.g. 'trading_loop', 'trade_executor'
|
|
* @param eventName Specific event, e.g. 'cycle_complete', 'order_filled'
|
|
* @param extra Optional extra fields (userId, tags, metrics, message)
|
|
*/
|
|
function trackEvent(
|
|
eventType: string,
|
|
module: string,
|
|
eventName: string,
|
|
extra?: {
|
|
feature?: string;
|
|
message?: string;
|
|
tags?: Record<string, string>;
|
|
metrics?: Record<string, number>;
|
|
userId?: string;
|
|
},
|
|
): void {
|
|
try {
|
|
client.trackEvent(eventType, module, eventName, extra);
|
|
} catch {
|
|
// Non-fatal
|
|
}
|
|
}
|
|
|
|
export const tradingTelemetry = { init, shutdown, trackEvent };
|