faf6ec826e
- Implemented standard empty and active chat conversation states for the `/intelligence` page - Created interactive `AiResponseRenderer` with AOT-compliant sentence splitting and payment gateway simulation - Added scoped `LibraryStateService` to synchronize book ownership and updates across the application - Obfuscated paywalled content in DOM to prevent inspection bypass - Fixed local port connection mismatch by updating API configurations to use port 5104
136 lines
7.8 KiB
C#
136 lines
7.8 KiB
C#
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<IPlatformService, WebPlatformService>();
|
|
builder.Services.AddScoped<INativeStorageService, WebStorageService>();
|
|
builder.Services.AddScoped<IThemeService, ThemeService>();
|
|
// Feature settings (avoiding direct raw IConfiguration injection in client pages)
|
|
var featureSettings = builder.Configuration.GetSection("Features").Get<FeatureSettings>() ?? new FeatureSettings();
|
|
builder.Services.AddSingleton(featureSettings);
|
|
builder.Services.AddScoped<IQuizStateService, QuizStateService>();
|
|
builder.Services.AddScoped<IFocusModeService, FocusModeService>();
|
|
builder.Services.AddScoped<IReaderNavigationService, ReaderNavigationService>();
|
|
builder.Services.AddScoped<IKnowledgeGraphService, KnowledgeGraphService>();
|
|
builder.Services.AddScoped<IReaderInteractionService, ReaderInteractionService>();
|
|
builder.Services.AddScoped<IReaderStateService, ReaderStateService>();
|
|
builder.Services.AddScoped<ILibraryStateService, LibraryStateService>();
|
|
builder.Services.AddScoped<KnowledgeCoordinator>();
|
|
builder.Services.AddScoped<ISyncService, SyncService>();
|
|
|
|
// Identity & Auth Services
|
|
builder.Services.AddOptions();
|
|
builder.Services.AddAuthorizationCore();
|
|
builder.Services.AddScoped<IIdentityService, IdentityService>();
|
|
builder.Services.AddScoped<NexusAuthenticationStateProvider>();
|
|
builder.Services.AddScoped<AuthenticationStateProvider>(sp => sp.GetRequiredService<NexusAuthenticationStateProvider>());
|
|
builder.Services.AddCascadingAuthenticationState();
|
|
|
|
// AI & Content Services
|
|
builder.Services.AddScoped<IKnowledgeService, WasmKnowledgeService>();
|
|
builder.Services.AddScoped<IConceptsMapService, WasmConceptsMapService>();
|
|
|
|
builder.Services.AddTransient<NexusReader.Web.Client.Handlers.AuthenticationHeaderHandler>();
|
|
builder.Services.AddHttpClient("NexusAPI", client =>
|
|
{
|
|
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
|
|
}).AddHttpMessageHandler<NexusReader.Web.Client.Handlers.AuthenticationHeaderHandler>();
|
|
|
|
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("NexusAPI"));
|
|
|
|
// Dummy registrations for server-only handlers to satisfy DI validation in WASM
|
|
builder.Services.AddSingleton<IDbContextFactory<AppDbContext>>(new ThrowingDbContextFactory());
|
|
builder.Services.AddSingleton<IEmbeddingGenerator<string, Embedding<float>>>(new ThrowingEmbeddingGenerator());
|
|
builder.Services.AddSingleton<IBookStorageService>(new ThrowingBookStorageService());
|
|
builder.Services.AddSingleton<IEbookRepository>(new ThrowingEbookRepository());
|
|
builder.Services.AddSingleton<IQuizResultRepository>(new ThrowingQuizResultRepository());
|
|
builder.Services.AddSingleton<IConceptsMapReadRepository>(new ThrowingConceptsMapReadRepository());
|
|
builder.Services.AddSingleton<ISyncBroadcaster>(new ThrowingSyncBroadcaster());
|
|
builder.Services.AddSingleton<IEpubExtractor>(new ThrowingEpubExtractor());
|
|
|
|
builder.Services.AddApplication();
|
|
builder.Services.AddScoped<IEpubReader, WasmEpubReader>();
|
|
builder.Services.AddScoped<IEpubMetadataExtractor, WasmEpubMetadataExtractor>();
|
|
|
|
await builder.Build().RunAsync();
|
|
|
|
public class ThrowingDbContextFactory : IDbContextFactory<AppDbContext>
|
|
{
|
|
public AppDbContext CreateDbContext() => throw new NotSupportedException("DbContext cannot be used in WASM client.");
|
|
}
|
|
|
|
public class ThrowingEmbeddingGenerator : IEmbeddingGenerator<string, Embedding<float>>
|
|
{
|
|
public void Dispose() { }
|
|
public Task<GeneratedEmbeddings<Embedding<float>>> GenerateAsync(IEnumerable<string> 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<string> SaveEbookAsync(byte[] data, string fileName) => throw new NotSupportedException(ErrorMessage);
|
|
public Task<string> SaveEbookAsync(Stream data, string fileName) => throw new NotSupportedException(ErrorMessage);
|
|
public Task<string?> SaveCoverAsync(byte[] data, string fileName) => throw new NotSupportedException(ErrorMessage);
|
|
public Task<string?> 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<Author?> 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<Ebook?> FindByIdAsync(Guid id, CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage);
|
|
public Task<int> 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<NexusUser?> FindUserByIdAsync(string userId, CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage);
|
|
public void AddQuizResult(QuizResult quizResult) => throw new NotSupportedException(ErrorMessage);
|
|
public Task<int> 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<string?> GetLastReadPageIdAsync(string userId, CancellationToken cancellationToken = default) => throw new NotSupportedException(ErrorMessage);
|
|
public Task<List<KnowledgeUnit>> 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<FluentResults.Result<List<string>>> ExtractChaptersTextAsync(string relativePath, CancellationToken cancellationToken = default)
|
|
=> throw new NotSupportedException("EPUB text extraction is not supported in the WASM client.");
|
|
}
|
|
|