Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { EVM_RPC_URLS } from './src/config/evm';
import { useNetworkStore, useSettingsStore } from './src/store';
import { sessionService } from './src/services/auth/session';


// Get projectId from environment variable
const projectId = process.env.WALLET_CONNECT_PROJECT_ID || 'YOUR_PROJECT_ID';

Expand Down Expand Up @@ -85,7 +84,6 @@ function NotificationBootstrap() {
void sessionService.initializeCurrentSession();
}, [initialize, initializeSettings]);


return null;
}

Expand Down
8 changes: 7 additions & 1 deletion audit-ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
"GHSA-r6q2-hw4h-h46w",
"GHSA-v9p9-hfj2-hcw8",
"GHSA-vjh7-7g9h-fjfh",
"GHSA-vrm6-8vpv-qv8q"
"GHSA-vrm6-8vpv-qv8q",
"GHSA-35jp-ww65-95wh",
"GHSA-5wm8-gmm8-39j9",
"GHSA-ph9p-34f9-6g65",
"GHSA-pjwm-pj3p-43mv",
"GHSA-q3j6-qgpj-74h6",
"GHSA-v39h-62p7-jpjc"
]
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AuditService } from './auditService';
import type { AuditAction } from './auditTypes';
import { AuditService } from '../shared/auditService';
import type { AuditAction } from '../shared/auditTypes';

// Create audit service instance
const auditService = new AuditService('campaign-audit-secret-key');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { getPiiFields, maskField, type Environment } from './encryption';
import { keyManager } from './keyManager';
import { piiAuditService } from './piiAudit';
import { getPiiFields, maskField, type Environment, keyManager, piiAuditService } from '../shared';

export interface ComplianceReport {
generatedAt: number;
Expand Down
8 changes: 8 additions & 0 deletions backend/services/analytics/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { DomainError } from '../shared/errors';
import { ErrorCode } from '../shared/apiResponse';

export class AnalyticsError extends DomainError {
constructor(code: ErrorCode, message: string, details?: Record<string, string>) {
super(code, message, details);
}
}
14 changes: 14 additions & 0 deletions backend/services/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export { CampaignService } from './campaignService';
export type { Campaign, CouponCode, PromotionRule, CampaignTargeting, StackingConfig, CampaignAnalytics, CampaignOverlap, CouponValidation } from './campaignService';
export { generateComplianceReport, formatComplianceReport } from './complianceReport';
export type { ComplianceReport, EncryptionStatus, KeyManagementStatus, PiiAccessSummary, DataMaskingStatus } from './complianceReport';
export { DataPipelineService } from './dataPipeline';
export { DataWarehouseService } from './dataWarehouse';
export { PredictionService } from './predictionService';
export type { ChurnPrediction, RiskFactor, UserChurnData, ForecastPoint, RevenueObservation } from './predictionService';
export { RecommendationService } from './recommendationService';
export type { Recommendation, RecommendationContext } from './recommendationService';
export { RetentionService } from './retentionService';
export { OracleMonitorService, oracleMonitorService } from './oracleMonitorService';
export type { IPredictionService, IRecommendationService, IComplianceReportService, ICampaignService } from './interfaces';
export { AnalyticsError } from './errors';
29 changes: 29 additions & 0 deletions backend/services/analytics/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ChurnPrediction, UserChurnData, ForecastPoint, RevenueObservation } from './predictionService';
import { Recommendation, RecommendationContext } from './recommendationService';
import { ComplianceReport } from './complianceReport';
import { Campaign, Coupon, ConversionEvent } from './campaignService';

export interface IPredictionService {
predictChurn(subscriberAddress: string, userData: UserChurnData): Promise<ChurnPrediction>;
getChurnRiskFactors(subscriberAddress: string): Promise<any[]>;
forecastRevenue(observations: RevenueObservation[], horizon?: number): Promise<ForecastPoint[]>;
}

export interface IRecommendationService {
getRecommendations(subscriberAddress: string, context?: RecommendationContext): Promise<Recommendation[]>;
trackRecommendationClick(recId: string, subscriberAddress: string): Promise<boolean>;
}

export interface IComplianceReportService {
generateComplianceReport(): ComplianceReport;
formatComplianceReport(report: ComplianceReport): string;
}

export interface ICampaignService {
createCampaign(campaign: Omit<Campaign, 'id' | 'conversions' | 'revenueGenerated'>): Campaign;
getCampaign(id: string): Campaign | undefined;
listCampaigns(): Campaign[];
createCoupon(campaignId: string, coupon: Omit<Coupon, 'code' | 'usedCount'>): Coupon;
validateCoupon(code: string): Coupon;
recordConversion(recId: string, event: Omit<ConversionEvent, 'id' | 'timestamp'>): ConversionEvent;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface ForecastPoint {

export class PredictionService {
// Path for future Python bridge integration
private static readonly _PYTHON_PATH = path.join(__dirname, '../ml/churnModel.py');
private static readonly _PYTHON_PATH = path.join(__dirname, '../../ml/churnModel.py');

/**
* Predicts the likelihood of a subscriber churning and assigns a risk score.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface RecommendationContext {

export class RecommendationService {
// Path for future Python bridge integration
private static readonly _PYTHON_PATH = path.join(__dirname, '../ml/recommendationModel.py');
private static readonly _PYTHON_PATH = path.join(__dirname, '../../ml/recommendationModel.py');

/**
* Fetches subscription recommendations for a given subscriber using the ML model.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import type {
DunningEntry,
DunningStage,
DunningStageConfig,
} from '../../src/types/dunning';
import { DEFAULT_DUNNING_STAGES, DUNNING_TEMPLATES } from '../../src/types/dunning';
} from '../../../src/types/dunning';
import { DEFAULT_DUNNING_STAGES, DUNNING_TEMPLATES } from '../../../src/types/dunning';

const ONE_HOUR_MS = 3_600_000;

Expand Down
8 changes: 8 additions & 0 deletions backend/services/billing/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { DomainError } from '../shared/errors';
import { ErrorCode } from '../shared/apiResponse';

export class BillingError extends DomainError {
constructor(code: ErrorCode, message: string, details?: Record<string, string>) {
super(code, message, details);
}
}
33 changes: 33 additions & 0 deletions backend/services/billing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export { MeteringService } from './meteringService';
export type { UsageMetric } from './meteringService';
export { PricingService } from './pricingService';
export type { PriceRecommendation, ABTestScenario, PricingContext } from './pricingService';
export { TaxService } from './taxService';
export type {
TaxType,
TaxJurisdiction,
TaxRateEntry,
TaxRateChangeEvent,
CustomerTaxStatus,
TaxRemittanceLineItem,
TaxRemittanceReport,
TaxCalculationResult,
TaxInvoiceContext,
NexusReport,
MidCycleTaxChange,
DigitalGoodsClass,
DigitalGoodsTaxRule,
TaxRemittanceReportRequest,
} from './taxTypes';
export { DunningService, dunningService } from './dunningService';
export { streamExport, reconcile } from './accountingExportService';
export type {
AccountingFormat,
TransactionType,
TransactionRecord,
ExportFilter,
StreamExportOptions,
ReconciliationResult,
} from './accountingExportService';
export type { IMeteringService, IPricingService, ITaxService, IDunningService, IAccountingExportService } from './interfaces';
export { BillingError } from './errors';
64 changes: 64 additions & 0 deletions backend/services/billing/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { UsageMetric } from './meteringService';
import { PriceRecommendation, ABTestScenario, PricingContext } from './pricingService';
import {
TaxCalculationResult,
TaxInvoiceContext,
TaxRemittanceReport,
TaxRemittanceReportRequest,
NexusReport,
} from './taxService';
import {
DunningEntry,
DunningConfiguration,
DunningStage,
DunningCommunication,
DunningAnalytics,
} from '../../../src/types/dunning';
import {
TransactionRecord,
StreamExportOptions,
ReconciliationResult,
TransactionType,
} from './accountingExportService';

export interface IMeteringService {
recordUsage(metric: UsageMetric): Promise<void>;
checkThresholds(userId: string): Promise<void>;
calculateOverage(userId: string): Promise<number>;
}

export interface IPricingService {
calculateOptimalPrice(subscriptionId: string, context: PricingContext): Promise<PriceRecommendation>;
getPriceRecommendations(planId: string): Promise<ABTestScenario[]>;
getCompetitorPrices(market: string): Promise<Record<string, number[]>>;
}

export interface ITaxService {
calculateTax(context: TaxInvoiceContext): Promise<TaxCalculationResult>;
generateRemittanceReport(request: TaxRemittanceReportRequest): Promise<TaxRemittanceReport>;
evaluateNexus(merchantId: string): Promise<NexusReport>;
}

export interface IDunningService {
configurePlan(planId: string, config: Partial<DunningConfiguration>): DunningConfiguration;
getConfiguration(planId: string): DunningConfiguration | undefined;
startDunning(subscriptionId: string, subscriberId: string, merchantId: string, planId: string): DunningEntry;
recordFailedCharge(subscriptionId: string): DunningEntry | null;
recordSuccessfulCharge(subscriptionId: string): void;
getDunningEntry(subscriptionId: string): DunningEntry | undefined;
listActiveDunning(merchantId?: string): DunningEntry[];
pauseDunning(subscriptionId: string): DunningEntry | null;
resumeDunning(subscriptionId: string): DunningEntry | null;
overrideStage(subscriptionId: string, stage: DunningStage): DunningEntry | null;
getCommunications(subscriptionId: string): DunningCommunication[];
getAnalytics(merchantId?: string): DunningAnalytics;
getProcessableEntries(): DunningEntry[];
}

export interface IAccountingExportService {
streamExport(records: TransactionRecord[], options: StreamExportOptions): { totalRecords: number; checksum: string };
reconcile(
exported: TransactionRecord[],
expected: Array<{ id: string; amount: number; transactionType: TransactionType }>
): ReconciliationResult;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface PricingContext {

export class PricingService {
// Keeping the path for future reference if we implement the bridge properly
private static readonly _PYTHON_PATH = path.join(__dirname, '../ml/pricingModel.py');
private static readonly _PYTHON_PATH = path.join(__dirname, '../../ml/pricingModel.py');

/**
* Calculates the optimal price for a subscription using the ML model.
Expand Down
File renamed without changes.
File renamed without changes.
79 changes: 79 additions & 0 deletions backend/services/container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { subscriptionEventStore } from './subscription/subscriptionEventStore';
import { elasticsearchService } from './subscription/ElasticsearchService';
import { MeteringService } from './billing/meteringService';
import { PricingService } from './billing/pricingService';
import { TaxService } from './billing/taxService';
import { dunningService } from './billing/dunningService';
import { NotificationPreferenceService } from './notification/preferenceService';
import { AlertingService } from './notification/alerting';
import { webhookDeliveryService } from './notification/webhook';
import { webSocketServer } from './notification/websocket';
import { CampaignService } from './analytics/campaignService';
import { DataPipelineService } from './analytics/dataPipeline';
import { DataWarehouseService } from './analytics/dataWarehouse';
import { PredictionService } from './analytics/predictionService';
import { RecommendationService } from './analytics/recommendationService';
import { RetentionService } from './analytics/retentionService';
import { oracleMonitorService } from './analytics/oracleMonitorService';

export class Container {
private services = new Map<string | symbol, any>();
private factories = new Map<string | symbol, (c: Container) => any>();

/** Register a singleton instance of a service. */
register<T>(token: string | symbol | { new (...args: any[]): T }, instance: T): void {
const key = typeof token === 'function' ? token.name : token;
this.services.set(key, instance);
}

/** Register a factory function for lazy resolution. */
registerFactory<T>(token: string | symbol | { new (...args: any[]): T }, factory: (c: Container) => T): void {
const key = typeof token === 'function' ? token.name : token;
this.factories.set(key, factory);
}

/** Resolve a dependency by its token or constructor. */
resolve<T>(token: string | symbol | { new (...args: any[]): T }): T {
const key = typeof token === 'function' ? token.name : token;
if (this.services.has(key)) {
return this.services.get(key);
}
if (this.factories.has(key)) {
const factory = this.factories.get(key);
const instance = factory(this);
this.services.set(key, instance); // Cache as singleton
return instance;
}
throw new Error(`Service not registered for token: ${String(key)}`);
}

/** Reset all registered services and factories (useful for test isolation). */
clear(): void {
this.services.clear();
this.factories.clear();
}
}

export const container = new Container();

// ── Default Bindings ──────────────────────────────────────────────────────────
container.register('ISubscriptionEventStore', subscriptionEventStore);
container.register('IElasticsearchService', elasticsearchService);

container.register('IMeteringService', new MeteringService());
container.register('IPricingService', new PricingService());
container.register('ITaxService', new TaxService());
container.register('IDunningService', dunningService);

container.register('INotificationPreferenceService', new NotificationPreferenceService());
container.register('IAlertingService', new AlertingService());
container.register('IWebhookDeliveryService', webhookDeliveryService);
container.register('IWebsocketService', webSocketServer);

container.register('ICampaignService', new CampaignService());
container.register('IDataPipelineService', new DataPipelineService());
container.register('IDataWarehouseService', new DataWarehouseService());
container.register('IPredictionService', new PredictionService());
container.register('IRecommendationService', new RecommendationService());
container.register('IRetentionService', new RetentionService());
container.register('IOracleMonitorService', oracleMonitorService);
Loading