mirror of
https://git.v0l.io/Kieran/void.cat.git
synced 2025-09-28 07:16:40 +02:00
Refactor metadata
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using VoidCat.Model;
|
using VoidCat.Model;
|
||||||
using VoidCat.Services;
|
|
||||||
using VoidCat.Services.Abstractions;
|
using VoidCat.Services.Abstractions;
|
||||||
|
|
||||||
namespace VoidCat.Controllers;
|
namespace VoidCat.Controllers;
|
||||||
@@ -32,9 +31,9 @@ public class DownloadController : Controller
|
|||||||
public async Task DownloadFile([FromRoute] string id)
|
public async Task DownloadFile([FromRoute] string id)
|
||||||
{
|
{
|
||||||
var gid = id.FromBase58Guid();
|
var gid = id.FromBase58Guid();
|
||||||
var meta = await SetupDownload(gid);
|
var voidFile = await SetupDownload(gid);
|
||||||
|
|
||||||
var egressReq = new EgressRequest(gid, GetRanges(Request, (long)meta!.Size));
|
var egressReq = new EgressRequest(gid, GetRanges(Request, (long) voidFile!.Metadata!.Size));
|
||||||
if (egressReq.Ranges.Count() > 1)
|
if (egressReq.Ranges.Count() > 1)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Multi-range request not supported!");
|
_logger.LogWarning("Multi-range request not supported!");
|
||||||
@@ -46,10 +45,10 @@ public class DownloadController : Controller
|
|||||||
}
|
}
|
||||||
else if (egressReq.Ranges.Count() == 1)
|
else if (egressReq.Ranges.Count() == 1)
|
||||||
{
|
{
|
||||||
Response.StatusCode = (int)HttpStatusCode.PartialContent;
|
Response.StatusCode = (int) HttpStatusCode.PartialContent;
|
||||||
if (egressReq.Ranges.Sum(a => a.Size) == 0)
|
if (egressReq.Ranges.Sum(a => a.Size) == 0)
|
||||||
{
|
{
|
||||||
Response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable;
|
Response.StatusCode = (int) HttpStatusCode.RequestedRangeNotSatisfiable;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +69,7 @@ public class DownloadController : Controller
|
|||||||
await Response.CompleteAsync();
|
await Response.CompleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<VoidFile?> SetupDownload(Guid id)
|
private async Task<PublicVoidFile?> SetupDownload(Guid id)
|
||||||
{
|
{
|
||||||
var meta = await _storage.Get(id);
|
var meta = await _storage.Get(id);
|
||||||
if (meta == null)
|
if (meta == null)
|
||||||
@@ -111,4 +110,4 @@ public class DownloadController : Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -23,11 +23,13 @@ namespace VoidCat.Controllers
|
|||||||
{
|
{
|
||||||
var bw = await _statsReporter.GetBandwidth();
|
var bw = await _statsReporter.GetBandwidth();
|
||||||
var bytes = 0UL;
|
var bytes = 0UL;
|
||||||
|
var count = 0;
|
||||||
await foreach (var vf in _fileStore.ListFiles())
|
await foreach (var vf in _fileStore.ListFiles())
|
||||||
{
|
{
|
||||||
bytes += vf.Size;
|
bytes += vf.Metadata?.Size ?? 0;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
return new(bw, bytes);
|
return new(bw, bytes, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -39,6 +41,6 @@ namespace VoidCat.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed record GlobalStats(Bandwidth Bandwidth, ulong TotalBytes);
|
public sealed record GlobalStats(Bandwidth Bandwidth, ulong TotalBytes, int Count);
|
||||||
public sealed record FileStats(Bandwidth Bandwidth);
|
public sealed record FileStats(Bandwidth Bandwidth);
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,9 @@ namespace VoidCat.Controllers
|
|||||||
var meta = new VoidFileMeta()
|
var meta = new VoidFileMeta()
|
||||||
{
|
{
|
||||||
MimeType = Request.Headers.GetHeader("V-Content-Type"),
|
MimeType = Request.Headers.GetHeader("V-Content-Type"),
|
||||||
Name = Request.Headers.GetHeader("V-Filename")
|
Name = Request.Headers.GetHeader("V-Filename"),
|
||||||
|
Description = Request.Headers.GetHeader("V-Description"),
|
||||||
|
Digest = Request.Headers.GetHeader("V-Full-Digest")
|
||||||
};
|
};
|
||||||
|
|
||||||
var digest = Request.Headers.GetHeader("V-Digest");
|
var digest = Request.Headers.GetHeader("V-Digest");
|
||||||
@@ -72,24 +74,10 @@ namespace VoidCat.Controllers
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("{id}")]
|
[Route("{id}")]
|
||||||
public ValueTask<VoidFile?> GetInfo([FromRoute] string id)
|
public ValueTask<PublicVoidFile?> GetInfo([FromRoute] string id)
|
||||||
{
|
{
|
||||||
return _storage.Get(id.FromBase58Guid());
|
return _storage.Get(id.FromBase58Guid());
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPatch]
|
|
||||||
[Route("{id}")]
|
|
||||||
public ValueTask UpdateFileInfo([FromRoute] string id, [FromBody] UpdateFileInfoRequest request)
|
|
||||||
{
|
|
||||||
return _storage.UpdateInfo(new VoidFile()
|
|
||||||
{
|
|
||||||
Id = id.FromBase58Guid(),
|
|
||||||
Metadata = request.Metadata
|
|
||||||
}, request.EditSecret);
|
|
||||||
}
|
|
||||||
|
|
||||||
public record UpdateFileInfoRequest([JsonConverter(typeof(Base58GuidConverter))] Guid EditSecret,
|
|
||||||
VoidFileMeta Metadata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||||
@@ -108,9 +96,9 @@ namespace VoidCat.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record UploadResult(bool Ok, InternalVoidFile? File, string? ErrorMessage)
|
public record UploadResult(bool Ok, PrivateVoidFile? File, string? ErrorMessage)
|
||||||
{
|
{
|
||||||
public static UploadResult Success(InternalVoidFile vf)
|
public static UploadResult Success(PrivateVoidFile vf)
|
||||||
=> new(true, vf, null);
|
=> new(true, vf, null);
|
||||||
|
|
||||||
public static UploadResult Error(string message)
|
public static UploadResult Error(string message)
|
||||||
|
30
VoidCat/Model/Paywall.cs
Normal file
30
VoidCat/Model/Paywall.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
namespace VoidCat.Model;
|
||||||
|
|
||||||
|
public record Paywall
|
||||||
|
{
|
||||||
|
public PaywallServices Service { get; init; }
|
||||||
|
|
||||||
|
public PaywallConfig? Config { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PaywallServices
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Strike
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PaywallCurrencies
|
||||||
|
{
|
||||||
|
BTC,
|
||||||
|
USD,
|
||||||
|
EUR,
|
||||||
|
GBP
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract record PaywallConfig
|
||||||
|
{
|
||||||
|
public PaywallCurrencies Currency { get; init; }
|
||||||
|
public decimal Cost { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record StrikePaywallConfig(string Handle) : PaywallConfig;
|
@@ -1,32 +1,31 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace VoidCat.Model
|
namespace VoidCat.Model
|
||||||
{
|
{
|
||||||
public record VoidFile
|
public abstract record VoidFile<TMeta> where TMeta : VoidFileMeta
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id of the file
|
||||||
|
/// </summary>
|
||||||
[JsonConverter(typeof(Base58GuidConverter))]
|
[JsonConverter(typeof(Base58GuidConverter))]
|
||||||
public Guid Id { get; init; }
|
public Guid Id { get; init; }
|
||||||
|
|
||||||
public VoidFileMeta? Metadata { get; set; }
|
|
||||||
|
|
||||||
public ulong Size { get; init; }
|
/// <summary>
|
||||||
|
/// Metadta related to the file
|
||||||
public DateTimeOffset Uploaded { get; init; }
|
/// </summary>
|
||||||
}
|
public TMeta? Metadata { get; init; }
|
||||||
|
|
||||||
public record InternalVoidFile : VoidFile
|
|
||||||
{
|
|
||||||
[JsonConverter(typeof(Base58GuidConverter))]
|
|
||||||
public Guid EditSecret { get; init; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public record VoidFileMeta
|
|
||||||
{
|
|
||||||
public string? Name { get; init; }
|
|
||||||
|
|
||||||
public string? Description { get; init; }
|
|
||||||
|
|
||||||
public string? MimeType { get; init; }
|
/// <summary>
|
||||||
|
/// Optional paywall config
|
||||||
|
/// </summary>
|
||||||
|
public Paywall? Paywall { get; init; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public sealed record PublicVoidFile : VoidFile<VoidFileMeta>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed record PrivateVoidFile : VoidFile<SecretVoidFileMeta>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
57
VoidCat/Model/VoidFileMeta.cs
Normal file
57
VoidCat/Model/VoidFileMeta.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using VoidCat.Services.Abstractions;
|
||||||
|
|
||||||
|
namespace VoidCat.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// File metadata which is managed by <see cref="IFileMetadataStore"/>
|
||||||
|
/// </summary>
|
||||||
|
public record VoidFileMeta
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Metadata version
|
||||||
|
/// </summary>
|
||||||
|
public int Version { get; init; } = 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filename
|
||||||
|
/// </summary>
|
||||||
|
public string? Name { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size of the file in storage
|
||||||
|
/// </summary>
|
||||||
|
public ulong Size { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Date file was uploaded
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset Uploaded { get; init; } = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Description about the file
|
||||||
|
/// </summary>
|
||||||
|
public string? Description { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The content type of the file
|
||||||
|
/// </summary>
|
||||||
|
public string? MimeType { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SHA-256 hash of the file
|
||||||
|
/// </summary>
|
||||||
|
public string? Digest { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="VoidFile"/> with attached <see cref="EditSecret"/>
|
||||||
|
/// </summary>
|
||||||
|
public record SecretVoidFileMeta : VoidFileMeta
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A secret key used to make edits to the file after its uploaded
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(Base58GuidConverter))]
|
||||||
|
public Guid EditSecret { get; init; }
|
||||||
|
}
|
@@ -6,6 +6,7 @@ using StackExchange.Redis;
|
|||||||
using VoidCat.Model;
|
using VoidCat.Model;
|
||||||
using VoidCat.Services;
|
using VoidCat.Services;
|
||||||
using VoidCat.Services.Abstractions;
|
using VoidCat.Services.Abstractions;
|
||||||
|
using VoidCat.Services.Migrations;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
var services = builder.Services;
|
var services = builder.Services;
|
||||||
@@ -41,6 +42,8 @@ services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// void.cat services
|
||||||
|
services.AddVoidMigrations();
|
||||||
services.AddScoped<IFileMetadataStore, LocalDiskFileMetadataStore>();
|
services.AddScoped<IFileMetadataStore, LocalDiskFileMetadataStore>();
|
||||||
services.AddScoped<IFileStore, LocalDiskFileStore>();
|
services.AddScoped<IFileStore, LocalDiskFileStore>();
|
||||||
services.AddScoped<IAggregateStatsCollector, AggregateStatsCollector>();
|
services.AddScoped<IAggregateStatsCollector, AggregateStatsCollector>();
|
||||||
@@ -61,6 +64,13 @@ else
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// run migrations
|
||||||
|
var migrations = app.Services.GetServices<IMigration>();
|
||||||
|
foreach (var migration in migrations)
|
||||||
|
{
|
||||||
|
await migration.Migrate();
|
||||||
|
}
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
@@ -4,9 +4,9 @@ namespace VoidCat.Services.Abstractions;
|
|||||||
|
|
||||||
public interface IFileMetadataStore
|
public interface IFileMetadataStore
|
||||||
{
|
{
|
||||||
ValueTask<InternalVoidFile?> Get(Guid id);
|
ValueTask<SecretVoidFileMeta?> Get(Guid id);
|
||||||
|
|
||||||
ValueTask Set(InternalVoidFile meta);
|
ValueTask Set(Guid id, SecretVoidFileMeta meta);
|
||||||
|
|
||||||
ValueTask Update(VoidFile patch, Guid editSecret);
|
ValueTask Update(Guid id, SecretVoidFileMeta patch);
|
||||||
}
|
}
|
||||||
|
@@ -4,15 +4,13 @@ namespace VoidCat.Services.Abstractions;
|
|||||||
|
|
||||||
public interface IFileStore
|
public interface IFileStore
|
||||||
{
|
{
|
||||||
ValueTask<VoidFile?> Get(Guid id);
|
ValueTask<PublicVoidFile?> Get(Guid id);
|
||||||
|
|
||||||
ValueTask<InternalVoidFile> Ingress(IngressPayload payload, CancellationToken cts);
|
ValueTask<PrivateVoidFile> Ingress(IngressPayload payload, CancellationToken cts);
|
||||||
|
|
||||||
ValueTask Egress(EgressRequest request, Stream outStream, CancellationToken cts);
|
ValueTask Egress(EgressRequest request, Stream outStream, CancellationToken cts);
|
||||||
|
|
||||||
ValueTask UpdateInfo(VoidFile patch, Guid editSecret);
|
IAsyncEnumerable<PublicVoidFile> ListFiles();
|
||||||
|
|
||||||
IAsyncEnumerable<VoidFile> ListFiles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed record IngressPayload(Stream InStream, VoidFileMeta Meta, string Hash)
|
public sealed record IngressPayload(Stream InStream, VoidFileMeta Meta, string Hash)
|
||||||
|
@@ -7,7 +7,7 @@ namespace VoidCat.Services;
|
|||||||
|
|
||||||
public class LocalDiskFileMetadataStore : IFileMetadataStore
|
public class LocalDiskFileMetadataStore : IFileMetadataStore
|
||||||
{
|
{
|
||||||
private const string MetadataDir = "metadata";
|
private const string MetadataDir = "metadata-v2";
|
||||||
private readonly VoidSettings _settings;
|
private readonly VoidSettings _settings;
|
||||||
|
|
||||||
public LocalDiskFileMetadataStore(VoidSettings settings)
|
public LocalDiskFileMetadataStore(VoidSettings settings)
|
||||||
@@ -21,34 +21,31 @@ public class LocalDiskFileMetadataStore : IFileMetadataStore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<InternalVoidFile?> Get(Guid id)
|
public async ValueTask<SecretVoidFileMeta?> Get(Guid id)
|
||||||
{
|
{
|
||||||
var path = MapMeta(id);
|
var path = MapMeta(id);
|
||||||
if (!File.Exists(path)) return default;
|
if (!File.Exists(path)) return default;
|
||||||
|
|
||||||
var json = await File.ReadAllTextAsync(path);
|
var json = await File.ReadAllTextAsync(path);
|
||||||
return JsonConvert.DeserializeObject<InternalVoidFile>(json);
|
return JsonConvert.DeserializeObject<SecretVoidFileMeta>(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask Set(InternalVoidFile meta)
|
public async ValueTask Set(Guid id, SecretVoidFileMeta meta)
|
||||||
{
|
{
|
||||||
var path = MapMeta(meta.Id);
|
var path = MapMeta(id);
|
||||||
var json = JsonConvert.SerializeObject(meta);
|
var json = JsonConvert.SerializeObject(meta);
|
||||||
await File.WriteAllTextAsync(path, json);
|
await File.WriteAllTextAsync(path, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask Update(VoidFile patch, Guid editSecret)
|
public async ValueTask Update(Guid id, SecretVoidFileMeta patch)
|
||||||
{
|
{
|
||||||
var oldMeta = await Get(patch.Id);
|
var oldMeta = await Get(id);
|
||||||
if (oldMeta?.EditSecret != editSecret)
|
if (oldMeta?.EditSecret != patch.EditSecret)
|
||||||
{
|
{
|
||||||
throw new VoidNotAllowedException("Edit secret incorrect");
|
throw new VoidNotAllowedException("Edit secret incorrect");
|
||||||
}
|
}
|
||||||
|
|
||||||
// only patch metadata
|
await Set(id, patch);
|
||||||
oldMeta.Metadata = patch.Metadata;
|
|
||||||
|
|
||||||
await Set(oldMeta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string MapMeta(Guid id) =>
|
private string MapMeta(Guid id) =>
|
||||||
|
@@ -26,9 +26,13 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<VoidFile?> Get(Guid id)
|
public async ValueTask<PublicVoidFile?> Get(Guid id)
|
||||||
{
|
{
|
||||||
return await _metadataStore.Get(id);
|
return new()
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Metadata = await _metadataStore.Get(id)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask Egress(EgressRequest request, Stream outStream, CancellationToken cts)
|
public async ValueTask Egress(EgressRequest request, Stream outStream, CancellationToken cts)
|
||||||
@@ -47,11 +51,11 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<InternalVoidFile> Ingress(IngressPayload payload, CancellationToken cts)
|
public async ValueTask<PrivateVoidFile> Ingress(IngressPayload payload, CancellationToken cts)
|
||||||
{
|
{
|
||||||
var id = payload.Id ?? Guid.NewGuid();
|
var id = payload.Id ?? Guid.NewGuid();
|
||||||
var fPath = MapPath(id);
|
var fPath = MapPath(id);
|
||||||
InternalVoidFile? vf = null;
|
SecretVoidFileMeta? vf = null;
|
||||||
if (payload.IsAppend)
|
if (payload.IsAppend)
|
||||||
{
|
{
|
||||||
vf = await _metadataStore.Get(payload.Id!.Value);
|
vf = await _metadataStore.Get(payload.Id!.Value);
|
||||||
@@ -81,10 +85,12 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vf = new InternalVoidFile()
|
vf = new SecretVoidFileMeta()
|
||||||
{
|
{
|
||||||
Id = id,
|
Name = payload.Meta.Name,
|
||||||
Metadata = payload.Meta,
|
Description = payload.Meta.Description,
|
||||||
|
Digest = payload.Meta.Digest,
|
||||||
|
MimeType = payload.Meta.MimeType,
|
||||||
Uploaded = DateTimeOffset.UtcNow,
|
Uploaded = DateTimeOffset.UtcNow,
|
||||||
EditSecret = Guid.NewGuid(),
|
EditSecret = Guid.NewGuid(),
|
||||||
Size = total
|
Size = total
|
||||||
@@ -92,16 +98,15 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
await _metadataStore.Set(vf);
|
await _metadataStore.Set(id, vf);
|
||||||
return vf;
|
return new()
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Metadata = vf
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask UpdateInfo(VoidFile patch, Guid editSecret)
|
public async IAsyncEnumerable<PublicVoidFile> ListFiles()
|
||||||
{
|
|
||||||
return _metadataStore.Update(patch, editSecret);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async IAsyncEnumerable<VoidFile> ListFiles()
|
|
||||||
{
|
{
|
||||||
foreach (var fe in Directory.EnumerateFiles(_settings.DataDirectory))
|
foreach (var fe in Directory.EnumerateFiles(_settings.DataDirectory))
|
||||||
{
|
{
|
||||||
@@ -111,7 +116,11 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
var meta = await _metadataStore.Get(id);
|
var meta = await _metadataStore.Get(id);
|
||||||
if (meta != default)
|
if (meta != default)
|
||||||
{
|
{
|
||||||
yield return meta;
|
yield return new()
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Metadata = meta
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,9 +143,9 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
var totalRead = readLength + offset;
|
var totalRead = readLength + offset;
|
||||||
var buf = buffer.Memory[..totalRead];
|
var buf = buffer.Memory[..totalRead];
|
||||||
await fs.WriteAsync(buf, cts);
|
await fs.WriteAsync(buf, cts);
|
||||||
await _stats.TrackIngress(id, (ulong)buf.Length);
|
await _stats.TrackIngress(id, (ulong) buf.Length);
|
||||||
sha.TransformBlock(buf.ToArray(), 0, buf.Length, null, 0);
|
sha.TransformBlock(buf.ToArray(), 0, buf.Length, null, 0);
|
||||||
total += (ulong)buf.Length;
|
total += (ulong) buf.Length;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +169,7 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
|
|
||||||
var fullSize = readLength + offset;
|
var fullSize = readLength + offset;
|
||||||
await outStream.WriteAsync(buffer.Memory[..fullSize], cts);
|
await outStream.WriteAsync(buffer.Memory[..fullSize], cts);
|
||||||
await _stats.TrackEgress(id, (ulong)fullSize);
|
await _stats.TrackEgress(id, (ulong) fullSize);
|
||||||
await outStream.FlushAsync(cts);
|
await outStream.FlushAsync(cts);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
@@ -188,8 +197,8 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
|
|
||||||
var fullSize = readLength + offset;
|
var fullSize = readLength + offset;
|
||||||
var toWrite = Math.Min(fullSize, dataRemaining);
|
var toWrite = Math.Min(fullSize, dataRemaining);
|
||||||
await outStream.WriteAsync(buffer.Memory[..(int)toWrite], cts);
|
await outStream.WriteAsync(buffer.Memory[..(int) toWrite], cts);
|
||||||
await _stats.TrackEgress(id, (ulong)toWrite);
|
await _stats.TrackEgress(id, (ulong) toWrite);
|
||||||
await outStream.FlushAsync(cts);
|
await outStream.FlushAsync(cts);
|
||||||
dataRemaining -= toWrite;
|
dataRemaining -= toWrite;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
@@ -204,4 +213,4 @@ public class LocalDiskFileStore : IFileStore
|
|||||||
|
|
||||||
private string MapPath(Guid id) =>
|
private string MapPath(Guid id) =>
|
||||||
Path.Join(_settings.DataDirectory, id.ToString());
|
Path.Join(_settings.DataDirectory, id.ToString());
|
||||||
}
|
}
|
116
VoidCat/Services/Migrations/20220217_MigrateMetadata.cs
Normal file
116
VoidCat/Services/Migrations/20220217_MigrateMetadata.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using VoidCat.Model;
|
||||||
|
|
||||||
|
namespace VoidCat.Services.Migrations;
|
||||||
|
|
||||||
|
public class MigrateMetadata_20220217 : IMigration
|
||||||
|
{
|
||||||
|
private const string MetadataDir = "metadata";
|
||||||
|
private const string MetadataV2Dir = "metadata-v2";
|
||||||
|
private readonly ILogger<MigrateMetadata_20220217> _logger;
|
||||||
|
private readonly VoidSettings _settings;
|
||||||
|
|
||||||
|
public MigrateMetadata_20220217(VoidSettings settings, ILogger<MigrateMetadata_20220217> log)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
_logger = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask Migrate()
|
||||||
|
{
|
||||||
|
var newMeta = Path.Combine(_settings.DataDirectory, MetadataV2Dir);
|
||||||
|
if (!Directory.Exists(newMeta))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(newMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var fe in Directory.EnumerateFiles(_settings.DataDirectory))
|
||||||
|
{
|
||||||
|
var filename = Path.GetFileNameWithoutExtension(fe);
|
||||||
|
if (!Guid.TryParse(filename, out var id)) continue;
|
||||||
|
|
||||||
|
var fp = MapMeta(id);
|
||||||
|
if (File.Exists(fp))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Migrating metadata for {file}", fp);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var oldJson = await File.ReadAllTextAsync(fp);
|
||||||
|
if(!oldJson.Contains("\"Metadata\":")) continue; // old format should contain "Metadata":
|
||||||
|
|
||||||
|
var old = JsonConvert.DeserializeObject<InternalVoidFile>(oldJson);
|
||||||
|
var newObj = new PrivateVoidFile()
|
||||||
|
{
|
||||||
|
Id = old!.Id,
|
||||||
|
Metadata = new()
|
||||||
|
{
|
||||||
|
Name = old.Metadata!.Name,
|
||||||
|
Description = old.Metadata.Description,
|
||||||
|
Uploaded = old.Uploaded,
|
||||||
|
MimeType = old.Metadata.MimeType,
|
||||||
|
EditSecret = old.EditSecret,
|
||||||
|
Size = old.Size
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(MapV2Meta(id), JsonConvert.SerializeObject(newObj));
|
||||||
|
|
||||||
|
// delete old metadata
|
||||||
|
File.Delete(fp);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string MapMeta(Guid id) =>
|
||||||
|
Path.ChangeExtension(Path.Join(_settings.DataDirectory, MetadataDir, id.ToString()), ".json");
|
||||||
|
private string MapV2Meta(Guid id) =>
|
||||||
|
Path.ChangeExtension(Path.Join(_settings.DataDirectory, MetadataV2Dir, id.ToString()), ".json");
|
||||||
|
|
||||||
|
private record VoidFile
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(Base58GuidConverter))]
|
||||||
|
public Guid Id { get; init; }
|
||||||
|
|
||||||
|
public VoidFileMeta? Metadata { get; set; }
|
||||||
|
|
||||||
|
public ulong Size { get; init; }
|
||||||
|
|
||||||
|
public DateTimeOffset Uploaded { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private record InternalVoidFile : VoidFile
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(Base58GuidConverter))]
|
||||||
|
public Guid EditSecret { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private record VoidFileMeta
|
||||||
|
{
|
||||||
|
public string? Name { get; init; }
|
||||||
|
|
||||||
|
public string? Description { get; init; }
|
||||||
|
|
||||||
|
public string? MimeType { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private record NewVoidFileMeta
|
||||||
|
{
|
||||||
|
public string? Name { get; init; }
|
||||||
|
public ulong Size { get; init; }
|
||||||
|
public DateTimeOffset Uploaded { get; init; } = DateTimeOffset.UtcNow;
|
||||||
|
public string? Description { get; init; }
|
||||||
|
public string? MimeType { get; init; }
|
||||||
|
public string? Digest { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private record NewSecretVoidFileMeta : NewVoidFileMeta
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(Base58GuidConverter))]
|
||||||
|
public Guid EditSecret { get; init; }
|
||||||
|
}
|
||||||
|
}
|
15
VoidCat/Services/Migrations/IMigration.cs
Normal file
15
VoidCat/Services/Migrations/IMigration.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace VoidCat.Services.Migrations;
|
||||||
|
|
||||||
|
public interface IMigration
|
||||||
|
{
|
||||||
|
ValueTask Migrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Migrations
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddVoidMigrations(this IServiceCollection svc)
|
||||||
|
{
|
||||||
|
svc.AddTransient<IMigration, MigrateMetadata_20220217>();
|
||||||
|
return svc;
|
||||||
|
}
|
||||||
|
}
|
@@ -4,14 +4,11 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"proxy": "https://localhost:7195",
|
"proxy": "https://localhost:7195",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"feather-icons-react": "^0.5.0",
|
||||||
"@testing-library/react": "^12.0.0",
|
|
||||||
"@testing-library/user-event": "^13.2.1",
|
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-router-dom": "^6.2.1",
|
"react-router-dom": "^6.2.1",
|
||||||
"react-scripts": "5.0.0",
|
"react-scripts": "5.0.0"
|
||||||
"web-vitals": "^2.1.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
@@ -3,7 +3,6 @@ import {useEffect, useState} from "react";
|
|||||||
import "./FileUpload.css";
|
import "./FileUpload.css";
|
||||||
import {buf2hex, ConstName, FormatBytes} from "./Util";
|
import {buf2hex, ConstName, FormatBytes} from "./Util";
|
||||||
import {RateCalculator} from "./RateCalculator";
|
import {RateCalculator} from "./RateCalculator";
|
||||||
import {upload} from "@testing-library/user-event/dist/upload";
|
|
||||||
|
|
||||||
const UploadState = {
|
const UploadState = {
|
||||||
NotStarted: 0,
|
NotStarted: 0,
|
||||||
|
@@ -2,4 +2,13 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
margin: 0 30px;
|
margin: 0 30px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats svg {
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats > div {
|
||||||
}
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
|
import FeatherIcon from "feather-icons-react";
|
||||||
import {FormatBytes} from "./Util";
|
import {FormatBytes} from "./Util";
|
||||||
|
|
||||||
import "./GlobalStats.css";
|
import "./GlobalStats.css";
|
||||||
@@ -16,13 +17,23 @@ export function GlobalStats(props) {
|
|||||||
useEffect(() => loadStats(), []);
|
useEffect(() => loadStats(), []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="stats">
|
<dl className="stats">
|
||||||
<div>Ingress:</div>
|
<div>
|
||||||
<div>{FormatBytes(stats?.bandwidth?.ingress ?? 0, 2)}</div>
|
<FeatherIcon icon="upload-cloud" />
|
||||||
<div>Egress:</div>
|
{FormatBytes(stats?.bandwidth?.ingress ?? 0, 2)}
|
||||||
<div>{FormatBytes(stats?.bandwidth?.egress ?? 0, 2)}</div>
|
</div>
|
||||||
<div>Storage:</div>
|
<div>
|
||||||
<div>{FormatBytes(stats?.totalBytes ?? 0, 2)}</div>
|
<FeatherIcon icon="download-cloud" />
|
||||||
</div>
|
{FormatBytes(stats?.bandwidth?.egress ?? 0, 2)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<FeatherIcon icon="database" />
|
||||||
|
{FormatBytes(stats?.totalBytes ?? 0, 2)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<FeatherIcon icon="hash" />
|
||||||
|
{stats?.count ?? 0}
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
);
|
);
|
||||||
}
|
}
|
@@ -1,17 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.css';
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import reportWebVitals from './reportWebVitals';
|
import './index.css';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
|
||||||
// to log results (for example: reportWebVitals(console.log))
|
|
||||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
|
||||||
reportWebVitals();
|
|
@@ -1,13 +0,0 @@
|
|||||||
const reportWebVitals = onPerfEntry => {
|
|
||||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
|
||||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
|
||||||
getCLS(onPerfEntry);
|
|
||||||
getFID(onPerfEntry);
|
|
||||||
getFCP(onPerfEntry);
|
|
||||||
getLCP(onPerfEntry);
|
|
||||||
getTTFB(onPerfEntry);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default reportWebVitals;
|
|
@@ -1,5 +0,0 @@
|
|||||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
|
||||||
// allows you to do things like:
|
|
||||||
// expect(element).toHaveTextContent(/react/i)
|
|
||||||
// learn more: https://github.com/testing-library/jest-dom
|
|
||||||
import '@testing-library/jest-dom';
|
|
@@ -1015,7 +1015,7 @@
|
|||||||
core-js-pure "^3.20.2"
|
core-js-pure "^3.20.2"
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.8.4":
|
||||||
version "7.16.7"
|
version "7.16.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa"
|
||||||
integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==
|
integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==
|
||||||
@@ -1491,50 +1491,6 @@
|
|||||||
"@svgr/plugin-svgo" "^5.5.0"
|
"@svgr/plugin-svgo" "^5.5.0"
|
||||||
loader-utils "^2.0.0"
|
loader-utils "^2.0.0"
|
||||||
|
|
||||||
"@testing-library/dom@^8.0.0":
|
|
||||||
version "8.11.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.11.2.tgz#fc110c665a066c2287be765e4a35ba8dad737015"
|
|
||||||
integrity sha512-idsS/cqbYudXcVWngc1PuWNmXs416oBy2g/7Q8QAUREt5Z3MUkAL2XJD7xazLJ6esDfqRDi/ZBxk+OPPXitHRw==
|
|
||||||
dependencies:
|
|
||||||
"@babel/code-frame" "^7.10.4"
|
|
||||||
"@babel/runtime" "^7.12.5"
|
|
||||||
"@types/aria-query" "^4.2.0"
|
|
||||||
aria-query "^5.0.0"
|
|
||||||
chalk "^4.1.0"
|
|
||||||
dom-accessibility-api "^0.5.9"
|
|
||||||
lz-string "^1.4.4"
|
|
||||||
pretty-format "^27.0.2"
|
|
||||||
|
|
||||||
"@testing-library/jest-dom@^5.14.1":
|
|
||||||
version "5.16.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.1.tgz#3db7df5ae97596264a7da9696fe14695ba02e51f"
|
|
||||||
integrity sha512-ajUJdfDIuTCadB79ukO+0l8O+QwN0LiSxDaYUTI4LndbbUsGi6rWU1SCexXzBA2NSjlVB9/vbkasQIL3tmPBjw==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.9.2"
|
|
||||||
"@types/testing-library__jest-dom" "^5.9.1"
|
|
||||||
aria-query "^5.0.0"
|
|
||||||
chalk "^3.0.0"
|
|
||||||
css "^3.0.0"
|
|
||||||
css.escape "^1.5.1"
|
|
||||||
dom-accessibility-api "^0.5.6"
|
|
||||||
lodash "^4.17.15"
|
|
||||||
redent "^3.0.0"
|
|
||||||
|
|
||||||
"@testing-library/react@^12.0.0":
|
|
||||||
version "12.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.2.tgz#f1bc9a45943461fa2a598bb4597df1ae044cfc76"
|
|
||||||
integrity sha512-ihQiEOklNyHIpo2Y8FREkyD1QAea054U0MVbwH1m8N9TxeFz+KoJ9LkqoKqJlzx2JDm56DVwaJ1r36JYxZM05g==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.12.5"
|
|
||||||
"@testing-library/dom" "^8.0.0"
|
|
||||||
|
|
||||||
"@testing-library/user-event@^13.2.1":
|
|
||||||
version "13.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-13.5.0.tgz#69d77007f1e124d55314a2b73fd204b333b13295"
|
|
||||||
integrity sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.12.5"
|
|
||||||
|
|
||||||
"@tootallnate/once@1":
|
"@tootallnate/once@1":
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||||
@@ -1545,11 +1501,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
|
||||||
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
|
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
|
||||||
|
|
||||||
"@types/aria-query@^4.2.0":
|
|
||||||
version "4.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
|
|
||||||
integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==
|
|
||||||
|
|
||||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14":
|
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14":
|
||||||
version "7.1.18"
|
version "7.1.18"
|
||||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8"
|
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8"
|
||||||
@@ -1704,14 +1655,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/istanbul-lib-report" "*"
|
"@types/istanbul-lib-report" "*"
|
||||||
|
|
||||||
"@types/jest@*":
|
|
||||||
version "27.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.0.tgz#037ab8b872067cae842a320841693080f9cb84ed"
|
|
||||||
integrity sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==
|
|
||||||
dependencies:
|
|
||||||
jest-diff "^27.0.0"
|
|
||||||
pretty-format "^27.0.0"
|
|
||||||
|
|
||||||
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
|
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
|
||||||
version "7.0.9"
|
version "7.0.9"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
|
||||||
@@ -1796,13 +1739,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
|
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
|
||||||
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
|
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
|
||||||
|
|
||||||
"@types/testing-library__jest-dom@^5.9.1":
|
|
||||||
version "5.14.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.2.tgz#564fb2b2dc827147e937a75b639a05d17ce18b44"
|
|
||||||
integrity sha512-vehbtyHUShPxIa9SioxDwCvgxukDMH//icJG90sXQBUm5lJOHLT5kNeU9tnivhnA/TkOFMzGIXN2cTc4hY8/kg==
|
|
||||||
dependencies:
|
|
||||||
"@types/jest" "*"
|
|
||||||
|
|
||||||
"@types/trusted-types@^2.0.2":
|
"@types/trusted-types@^2.0.2":
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756"
|
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756"
|
||||||
@@ -2241,11 +2177,6 @@ aria-query@^4.2.2:
|
|||||||
"@babel/runtime" "^7.10.2"
|
"@babel/runtime" "^7.10.2"
|
||||||
"@babel/runtime-corejs3" "^7.10.2"
|
"@babel/runtime-corejs3" "^7.10.2"
|
||||||
|
|
||||||
aria-query@^5.0.0:
|
|
||||||
version "5.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c"
|
|
||||||
integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==
|
|
||||||
|
|
||||||
array-flatten@1.1.1:
|
array-flatten@1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||||
@@ -2322,11 +2253,6 @@ at-least-node@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
|
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
|
||||||
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
|
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
|
||||||
|
|
||||||
atob@^2.1.2:
|
|
||||||
version "2.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
|
||||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
|
||||||
|
|
||||||
autoprefixer@^10.4.2:
|
autoprefixer@^10.4.2:
|
||||||
version "10.4.2"
|
version "10.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b"
|
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b"
|
||||||
@@ -2688,14 +2614,6 @@ chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
|
|||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
chalk@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
|
|
||||||
integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^4.1.0"
|
|
||||||
supports-color "^7.1.0"
|
|
||||||
|
|
||||||
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
|
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||||
@@ -3087,20 +3005,6 @@ css-what@^5.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe"
|
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe"
|
||||||
integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==
|
integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==
|
||||||
|
|
||||||
css.escape@^1.5.1:
|
|
||||||
version "1.5.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
|
|
||||||
integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=
|
|
||||||
|
|
||||||
css@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d"
|
|
||||||
integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==
|
|
||||||
dependencies:
|
|
||||||
inherits "^2.0.4"
|
|
||||||
source-map "^0.6.1"
|
|
||||||
source-map-resolve "^0.6.0"
|
|
||||||
|
|
||||||
cssdb@^5.0.0:
|
cssdb@^5.0.0:
|
||||||
version "5.1.0"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-5.1.0.tgz#ec728d5f5c0811debd0820cbebda505d43003400"
|
resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-5.1.0.tgz#ec728d5f5c0811debd0820cbebda505d43003400"
|
||||||
@@ -3224,11 +3128,6 @@ decimal.js@^10.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
|
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
|
||||||
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
|
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
|
||||||
|
|
||||||
decode-uri-component@^0.2.0:
|
|
||||||
version "0.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
|
||||||
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
|
|
||||||
|
|
||||||
dedent@^0.7.0:
|
dedent@^0.7.0:
|
||||||
version "0.7.0"
|
version "0.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
|
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
|
||||||
@@ -3392,11 +3291,6 @@ doctrine@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9:
|
|
||||||
version "0.5.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.10.tgz#caa6d08f60388d0bb4539dd75fe458a9a1d0014c"
|
|
||||||
integrity sha512-Xu9mD0UjrJisTmv7lmVSDMagQcU9R5hwAbxsaAE/35XPnPLJobbuREfV/rraiSaEj/UOvgrzQs66zyTWTlyd+g==
|
|
||||||
|
|
||||||
dom-converter@^0.2.0:
|
dom-converter@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
|
resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
|
||||||
@@ -4012,6 +3906,11 @@ fb-watchman@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
bser "2.1.1"
|
bser "2.1.1"
|
||||||
|
|
||||||
|
feather-icons-react@^0.5.0:
|
||||||
|
version "0.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/feather-icons-react/-/feather-icons-react-0.5.0.tgz#74f8b398f4031491901aa47ff470899e408df159"
|
||||||
|
integrity sha512-k7y6JnghcwLi3uo5SaSnnngfHOE+IPpAFzlsmNhlXwbP8jev2rOYbEq1g5lhMglbV934KhcaSbo3DYV32I3/Ug==
|
||||||
|
|
||||||
file-entry-cache@^6.0.1:
|
file-entry-cache@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
||||||
@@ -4603,7 +4502,7 @@ inflight@^1.0.4:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
|
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
@@ -4973,7 +4872,7 @@ jest-config@^27.4.7:
|
|||||||
pretty-format "^27.4.6"
|
pretty-format "^27.4.6"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
jest-diff@^27.0.0, jest-diff@^27.4.6:
|
jest-diff@^27.4.6:
|
||||||
version "27.4.6"
|
version "27.4.6"
|
||||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.6.tgz#93815774d2012a2cbb6cf23f84d48c7a2618f98d"
|
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.6.tgz#93815774d2012a2cbb6cf23f84d48c7a2618f98d"
|
||||||
integrity sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==
|
integrity sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==
|
||||||
@@ -5589,7 +5488,7 @@ lodash.uniq@^4.5.0:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||||
|
|
||||||
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
|
lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
@@ -5615,11 +5514,6 @@ lru-cache@^6.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist "^4.0.0"
|
yallist "^4.0.0"
|
||||||
|
|
||||||
lz-string@^1.4.4:
|
|
||||||
version "1.4.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
|
|
||||||
integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=
|
|
||||||
|
|
||||||
magic-string@^0.25.0, magic-string@^0.25.7:
|
magic-string@^0.25.0, magic-string@^0.25.7:
|
||||||
version "0.25.7"
|
version "0.25.7"
|
||||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
|
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
|
||||||
@@ -5713,11 +5607,6 @@ mimic-fn@^2.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||||
|
|
||||||
min-indent@^1.0.0:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
|
||||||
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
|
||||||
|
|
||||||
mini-css-extract-plugin@^2.4.5:
|
mini-css-extract-plugin@^2.4.5:
|
||||||
version "2.5.3"
|
version "2.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9"
|
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz#c5c79f9b22ce9b4f164e9492267358dbe35376d9"
|
||||||
@@ -6737,7 +6626,7 @@ pretty-error@^4.0.0:
|
|||||||
lodash "^4.17.20"
|
lodash "^4.17.20"
|
||||||
renderkid "^3.0.0"
|
renderkid "^3.0.0"
|
||||||
|
|
||||||
pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.4.6:
|
pretty-format@^27.4.6:
|
||||||
version "27.4.6"
|
version "27.4.6"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.6.tgz#1b784d2f53c68db31797b2348fa39b49e31846b7"
|
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.6.tgz#1b784d2f53c68db31797b2348fa39b49e31846b7"
|
||||||
integrity sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==
|
integrity sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==
|
||||||
@@ -7027,14 +6916,6 @@ recursive-readdir@^2.2.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
minimatch "3.0.4"
|
minimatch "3.0.4"
|
||||||
|
|
||||||
redent@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
|
|
||||||
integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
|
|
||||||
dependencies:
|
|
||||||
indent-string "^4.0.0"
|
|
||||||
strip-indent "^3.0.0"
|
|
||||||
|
|
||||||
regenerate-unicode-properties@^9.0.0:
|
regenerate-unicode-properties@^9.0.0:
|
||||||
version "9.0.0"
|
version "9.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326"
|
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326"
|
||||||
@@ -7477,14 +7358,6 @@ source-map-loader@^3.0.0:
|
|||||||
iconv-lite "^0.6.3"
|
iconv-lite "^0.6.3"
|
||||||
source-map-js "^1.0.1"
|
source-map-js "^1.0.1"
|
||||||
|
|
||||||
source-map-resolve@^0.6.0:
|
|
||||||
version "0.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2"
|
|
||||||
integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==
|
|
||||||
dependencies:
|
|
||||||
atob "^2.1.2"
|
|
||||||
decode-uri-component "^0.2.0"
|
|
||||||
|
|
||||||
source-map-support@^0.5.6, source-map-support@~0.5.20:
|
source-map-support@^0.5.6, source-map-support@~0.5.20:
|
||||||
version "0.5.21"
|
version "0.5.21"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
||||||
@@ -7692,13 +7565,6 @@ strip-final-newline@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||||
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
|
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
|
||||||
|
|
||||||
strip-indent@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
|
|
||||||
integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
|
|
||||||
dependencies:
|
|
||||||
min-indent "^1.0.0"
|
|
||||||
|
|
||||||
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
|
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||||
@@ -8184,11 +8050,6 @@ wbuf@^1.1.0, wbuf@^1.7.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.0"
|
||||||
|
|
||||||
web-vitals@^2.1.0:
|
|
||||||
version "2.1.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-2.1.4.tgz#76563175a475a5e835264d373704f9dde718290c"
|
|
||||||
integrity sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==
|
|
||||||
|
|
||||||
webidl-conversions@^4.0.2:
|
webidl-conversions@^4.0.2:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||||
|
Reference in New Issue
Block a user