using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.AspNetCore.Components.Authorization; using NexusReader.Application.Abstractions.Services; using NexusReader.Web.Client.Services; using NexusReader.UI.Shared.Services; using NexusReader.Application; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.AI; using NexusReader.Data.Persistence; using NexusReader.Application.Abstractions.Persistence; using NexusReader.Application.Abstractions.Messaging; using NexusReader.Domain.Entities; var builder = WebAssemblyHostBuilder.CreateDefault(args); // Platform & UI Services builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Feature settings (avoiding direct raw IConfiguration injection in client pages) var featureSettings = builder.Configuration.GetSection("Features").Get() ?? new FeatureSettings(); builder.Services.AddSingleton(featureSettings); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Identity & Auth Services builder.Services.AddOptions(); builder.Services.AddAuthorizationCore(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(sp => sp.GetRequiredService()); builder.Services.AddCascadingAuthenticationState(); // AI & Content Services builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddTransient(); builder.Services.AddHttpClient("NexusAPI", client => { client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress); }).AddHttpMessageHandler(); builder.Services.AddScoped(sp => sp.GetRequiredService().CreateClient("NexusAPI")); // Dummy registrations for server-only handlers to satisfy DI validation in WASM builder.Services.AddSingleton>(new ThrowingDbContextFactory()); builder.Services.AddSingleton>>(new ThrowingEmbeddingGenerator()); builder.Services.AddSingleton(new ThrowingBookStorageService()); builder.Services.AddSingleton(new ThrowingEbookRepository()); builder.Services.AddSingleton(new ThrowingQuizResultRepository()); builder.Services.AddSingleton(new ThrowingConceptsMapReadRepository()); builder.Services.AddSingleton(new ThrowingSyncBroadcaster()); builder.Services.AddSingleton(new ThrowingEpubExtractor()); builder.Services.AddApplication(); builder.Services.AddScoped(); builder.Services.AddScoped(); await builder.Build().RunAsync(); public class ThrowingDbContextFactory : IDbContextFactory { public AppDbContext CreateDbContext() => throw new NotSupportedException("DbContext cannot be used in WASM client."); } public class ThrowingEmbeddingGenerator : IEmbeddingGenerator> { public void Dispose() { } public Task>> GenerateAsync(IEnumerable values, EmbeddingGenerationOptions? options = null, CancellationToken cancellationToken = default) => throw new NotSupportedException("Embedding generation cannot be used in WASM client."); public object? GetService(Type serviceType, object? serviceKey = null) => null; } public class ThrowingBookStorageService : IBookStorageService { private const string ErrorMessage = "File storage operations are not supported in the WASM client. Use the API endpoint for ingestion."; public Task SaveEbookAsync(byte[] data, string fileName) => throw new NotSupportedException(ErrorMessage); public Task SaveEbookAsync(Stream data, string fileName) => throw new NotSupportedException(ErrorMessage); public Task SaveCoverAsync(byte[] data, string fileName) => throw new NotSupportedException(ErrorMessage); public Task SaveCoverAsync(Stream data, string fileName) => throw new NotSupportedException(ErrorMessage); } public class ThrowingEbookRepository : IEbookRepository { private const string ErrorMessage = "Ebook repository operations are not supported in the WASM client. Use the API endpoint for data access."; public Task FindAuthorByNameAsync(string name, CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage); public void AddAuthor(Author author) => throw new NotSupportedException(ErrorMessage); public void AddEbook(Ebook ebook) => throw new NotSupportedException(ErrorMessage); public Task FindByIdAsync(Guid id, CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage); public Task SaveChangesAsync(CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage); } public class ThrowingQuizResultRepository : IQuizResultRepository { private const string ErrorMessage = "QuizResult repository operations are not supported in the WASM client. Use the API endpoint for data access."; public Task FindUserByIdAsync(string userId, CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage); public void AddQuizResult(QuizResult quizResult) => throw new NotSupportedException(ErrorMessage); public Task SaveChangesAsync(CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage); } public class ThrowingConceptsMapReadRepository : IConceptsMapReadRepository { private const string ErrorMessage = "ConceptsMap repository operations are not supported in the WASM client. Use the API endpoint for data access."; public Task GetLastReadPageIdAsync(string userId, CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage); public Task> GetKnowledgeUnitsForBookAsync(Guid bookId, string tenantId, CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage); } public class ThrowingSyncBroadcaster : ISyncBroadcaster { public Task BroadcastProgressAsync(string userId, string pageId, DateTime timestamp, string? excludedConnectionId, CancellationToken cancellationToken = default) => throw new NotSupportedException("Real-time broadcasting can only be performed by the server."); public Task BroadcastIngestionProgressAsync(string userId, string message, double progress, CancellationToken cancellationToken = default) => throw new NotSupportedException("Real-time broadcasting can only be performed by the server."); } public class ThrowingEpubExtractor : IEpubExtractor { public Task>> ExtractChaptersTextAsync(string relativePath, CancellationToken cancellationToken = default) => throw new NotSupportedException("EPUB text extraction is not supported in the WASM client."); }