feat(transport): add IBundleExporter / IBundleImporter interfaces

This commit is contained in:
Joseph Doherty
2026-05-24 03:47:27 -04:00
parent 7e89f2092f
commit 9442c9a92c
9 changed files with 107 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
namespace ScadaLink.Commons.Interfaces.Transport;
/// <summary>
/// Scoped service the bundle importer sets to thread a BundleImportId through to
/// the audit log entries emitted by the audited repository methods invoked during
/// ApplyAsync. AuditService reads this and stamps every AuditLogEntry it writes.
/// </summary>
public interface IAuditCorrelationContext
{
Guid? BundleImportId { get; set; }
}

View File

@@ -0,0 +1,13 @@
using ScadaLink.Commons.Types.Transport;
namespace ScadaLink.Commons.Interfaces.Transport;
public interface IBundleExporter
{
Task<Stream> ExportAsync(
ExportSelection selection,
string user,
string sourceEnvironment,
string? passphrase,
CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,14 @@
using ScadaLink.Commons.Types.Transport;
namespace ScadaLink.Commons.Interfaces.Transport;
public interface IBundleImporter
{
Task<BundleSession> LoadAsync(Stream bundleStream, string? passphrase, CancellationToken ct = default);
Task<ImportPreview> PreviewAsync(Guid sessionId, CancellationToken ct = default);
Task<ImportResult> ApplyAsync(
Guid sessionId,
IReadOnlyList<ImportResolution> resolutions,
string user,
CancellationToken ct = default);
}

View File

@@ -0,0 +1,11 @@
using ScadaLink.Commons.Types.Transport;
namespace ScadaLink.Commons.Interfaces.Transport;
public interface IBundleSessionStore
{
BundleSession Open(BundleSession session);
BundleSession? Get(Guid sessionId);
void Remove(Guid sessionId);
void EvictExpired();
}

View File

@@ -0,0 +1,11 @@
namespace ScadaLink.Commons.Types.Transport;
public sealed class BundleSession
{
public Guid SessionId { get; init; }
public BundleManifest Manifest { get; init; } = null!;
public byte[] DecryptedContent { get; init; } = Array.Empty<byte>();
public DateTimeOffset ExpiresAt { get; init; }
public int FailedUnlockAttempts { get; set; }
public bool Locked => FailedUnlockAttempts >= 3;
}

View File

@@ -0,0 +1,12 @@
namespace ScadaLink.Commons.Types.Transport;
public sealed record ExportSelection(
IReadOnlyList<int> TemplateIds,
IReadOnlyList<int> SharedScriptIds,
IReadOnlyList<int> ExternalSystemIds,
IReadOnlyList<int> DatabaseConnectionIds,
IReadOnlyList<int> NotificationListIds,
IReadOnlyList<int> SmtpConfigurationIds,
IReadOnlyList<int> ApiKeyIds,
IReadOnlyList<int> ApiMethodIds,
bool IncludeDependencies);

View File

@@ -0,0 +1,16 @@
namespace ScadaLink.Commons.Types.Transport;
public enum ConflictKind { Identical, Modified, New, Blocker }
public sealed record ImportPreviewItem(
string EntityType,
string Name,
int? ExistingVersion,
int? IncomingVersion,
ConflictKind Kind,
string? FieldDiffJson,
string? BlockerReason);
public sealed record ImportPreview(
Guid SessionId,
IReadOnlyList<ImportPreviewItem> Items);

View File

@@ -0,0 +1,9 @@
namespace ScadaLink.Commons.Types.Transport;
public enum ResolutionAction { Add, Overwrite, Skip, Rename }
public sealed record ImportResolution(
string EntityType,
string Name,
ResolutionAction Action,
string? RenameTo);

View File

@@ -0,0 +1,10 @@
namespace ScadaLink.Commons.Types.Transport;
public sealed record ImportResult(
Guid BundleImportId,
int Added,
int Overwritten,
int Skipped,
int Renamed,
IReadOnlyList<int> StaleInstanceIds,
string AuditEventCorrelation);