diff --git a/MintPlayer.Dotnet.Tools.sln b/MintPlayer.Dotnet.Tools.sln
index 72b0afc4..f9c5703b 100644
--- a/MintPlayer.Dotnet.Tools.sln
+++ b/MintPlayer.Dotnet.Tools.sln
@@ -75,6 +75,26 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Verz", "Verz", "{0D1D2D90-B
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz", "Verz\MintPlayer.Verz\MintPlayer.Verz.csproj", "{D93E38AC-5865-4455-A94A-33B66C6328BE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz.Sdk.Dotnet", "Verz\Sdks\MintPlayer.Verz.Sdk.Dotnet\MintPlayer.Verz.Sdk.Dotnet.csproj", "{88F428E7-7505-4E11-8C2A-AD5581B63608}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdks", "Sdks", "{AF872388-3655-45E5-9A48-849A50D0C90F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Registries", "Registries", "{E0414AFD-FC74-438B-8A76-5629421AFEBA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz.Registry.NugetOrg", "Verz\Registries\MintPlayer.Verz.Registry.NugetOrg\MintPlayer.Verz.Registry.NugetOrg.csproj", "{7F0186AA-28B4-4FCF-84F8-0CF194F383F7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz.Registry.GithubPackageRegistry", "Verz\Registries\MintPlayer.Verz.Registry.GithubPackageRegistry\MintPlayer.Verz.Registry.GithubPackageRegistry.csproj", "{C6B6C78A-AD7B-4016-8447-FEE4DAB4C056}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz.Abstractions", "Verz\MintPlayer.Verz.Abstractions\MintPlayer.Verz.Abstractions.csproj", "{CFD067BC-C012-4CF4-9388-4880D9B48AEF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz.Sdk.Nodejs", "Verz\Sdks\MintPlayer.Verz.Sdk.Nodejs\MintPlayer.Verz.Sdk.Nodejs.csproj", "{A7262DE6-BD19-4CB4-BE58-31FA2991708F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz.Registry.NpmjsCom", "Verz\Registries\MintPlayer.Verz.Registry.NpmjsCom\MintPlayer.Verz.Registry.NpmjsCom.csproj", "{C25F28C9-3E97-4A6E-BCF2-86ABA65E19B2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz.Sdk.Dotnet.Abstractions", "Verz\Sdks\MintPlayer.Verz.Sdk.Dotnet.Abstractions\MintPlayer.Verz.Sdk.Dotnet.Abstractions.csproj", "{DED5D1B6-9410-4505-99EF-EC0E935FFE3C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.Verz.Sdk.Nodejs.Abstractions", "Verz\Sdks\MintPlayer.Verz.Sdk.Nodejs.Abstractions\MintPlayer.Verz.Sdk.Nodejs.Abstractions.csproj", "{97961B06-5204-49E1-B49A-FCB79D9711ED}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.ObservableCollection.Extensions", "ObservableCollection\MintPlayer.ObservableCollection.Extensions\MintPlayer.ObservableCollection.Extensions.csproj", "{0833621C-AFB4-4E25-9A4D-7B2E44CA7E05}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.ObservableCollection.Avalonia.Desktop", "ObservableCollection\AvaloniaTest\MintPlayer.ObservableCollection.Avalonia.Desktop\MintPlayer.ObservableCollection.Avalonia.Desktop.csproj", "{0BFF0671-2B0D-49BE-A583-FE087034AB11}"
@@ -91,6 +111,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.SourceGenerators
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InterfaceImplementationDebugging", "SourceGenerators\TestProjects\InterfaceImplementationDebugging\InterfaceImplementationDebugging.csproj", "{ABA2F1E2-B21B-425D-AB54-CC9EF317ADED}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiHash", "ApiHash", "{8972C435-9AB8-4C2A-AB33-A372D731F3DD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.ApiHash", "Verz\ApiHash\MintPlayer.ApiHash\MintPlayer.ApiHash.csproj", "{691498D2-8DD4-4E04-AEB5-05E8279A57E1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -193,6 +217,40 @@ Global
{D93E38AC-5865-4455-A94A-33B66C6328BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D93E38AC-5865-4455-A94A-33B66C6328BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D93E38AC-5865-4455-A94A-33B66C6328BE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {88F428E7-7505-4E11-8C2A-AD5581B63608}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {88F428E7-7505-4E11-8C2A-AD5581B63608}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {88F428E7-7505-4E11-8C2A-AD5581B63608}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {88F428E7-7505-4E11-8C2A-AD5581B63608}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F0186AA-28B4-4FCF-84F8-0CF194F383F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F0186AA-28B4-4FCF-84F8-0CF194F383F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F0186AA-28B4-4FCF-84F8-0CF194F383F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F0186AA-28B4-4FCF-84F8-0CF194F383F7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C6B6C78A-AD7B-4016-8447-FEE4DAB4C056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C6B6C78A-AD7B-4016-8447-FEE4DAB4C056}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C6B6C78A-AD7B-4016-8447-FEE4DAB4C056}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C6B6C78A-AD7B-4016-8447-FEE4DAB4C056}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CFD067BC-C012-4CF4-9388-4880D9B48AEF}.Debug|Any CPU.Active78A-AD7B-4016-8447-FEE4DAB4C056}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C6B6C78A-AD7B-4016-8447-FEE4DAB4C056}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CFD067BC-C012-4CF4-9388-4880D9B48AEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CFD067BC-C012-4CF4-9388-4880D9B48AEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CFD067BC-C012-4CF4-9388-4880D9B48AEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CFD067BC-C012-4CF4-9388-4880D9B48AEF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A7262DE6-BD19-4CB4-BE58-31FA2991708F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A7262DE6-BD19-4CB4-BE58-31FA2991708F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A7262DE6-BD19-4CB4-BE58-31FA2991708F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A7262DE6-BD19-4CB4-BE58-31FA2991708F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C25F28C9-3E97-4A6E-BCF2-86ABA65E19B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C25F28C9-3E97-4A6E-BCF2-86ABA65E19B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C25F28C9-3E97-4A6E-BCF2-86ABA65E19B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C25F28C9-3E97-4A6E-BCF2-86ABA65E19B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DED5D1B6-9410-4505-99EF-EC0E935FFE3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DED5D1B6-9410-4505-99EF-EC0E935FFE3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DED5D1B6-9410-4505-99EF-EC0E935FFE3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DED5D1B6-9410-4505-99EF-EC0E935FFE3C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {97961B06-5204-49E1-B49A-FCB79D9711ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {97961B06-5204-49E1-B49A-FCB79D9711ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {97961B06-5204-49E1-B49A-FCB79D9711ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {97961B06-5204-49E1-B49A-FCB79D9711ED}.Release|Any CPU.Build.0 = Release|Any CPU
{0833621C-AFB4-4E25-9A4D-7B2E44CA7E05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0833621C-AFB4-4E25-9A4D-7B2E44CA7E05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0833621C-AFB4-4E25-9A4D-7B2E44CA7E05}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -217,6 +275,10 @@ Global
{ABA2F1E2-B21B-425D-AB54-CC9EF317ADED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABA2F1E2-B21B-425D-AB54-CC9EF317ADED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABA2F1E2-B21B-425D-AB54-CC9EF317ADED}.Release|Any CPU.Build.0 = Release|Any CPU
+ {691498D2-8DD4-4E04-AEB5-05E8279A57E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {691498D2-8DD4-4E04-AEB5-05E8279A57E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {691498D2-8DD4-4E04-AEB5-05E8279A57E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {691498D2-8DD4-4E04-AEB5-05E8279A57E1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -246,6 +308,17 @@ Global
{82C6CB67-DDC0-4791-B975-39A970BD4CDC} = {C65054D9-CAD1-4124-B474-D03C178D9D78}
{6F4991E0-B4D8-43BA-92C0-15DD37ED7CD3} = {C65054D9-CAD1-4124-B474-D03C178D9D78}
{D93E38AC-5865-4455-A94A-33B66C6328BE} = {0D1D2D90-BCFA-47EE-8C72-2E10405F96DF}
+ {88F428E7-7505-4E11-8C2A-AD5581B63608} = {AF872388-3655-45E5-9A48-849A50D0C90F}
+ {AF872388-3655-45E5-9A48-849A50D0C90F} = {0D1D2D90-BCFA-47EE-8C72-2E10405F96DF}
+ {E0414AFD-FC74-438B-8A76-5629421AFEBA} = {0D1D2D90-BCFA-47EE-8C72-2E10405F96DF}
+ {7F0186AA-28B4-4FCF-84F8-0CF194F383F7} = {E0414AFD-FC74-438B-8A76-5629421AFEBA}
+ {C6B6C78A-AD7B-4016-8447-FEE4DAB4C056} = {E0414AFD-FC74-438B-8A76-5629421AFEBA}
+ {CFD067BC-C012-4CF4-9388-4880D9B48AEF} = {0D1D2D90-BCFA-47EE-8C72-2E10405F96DF}
+ {A7262DE6-BD19-4CB4-BE58-31FA2991708F} = {AF872388-3655-45E5-9A48-849A50D0C90F}
+ {C25F28C9-3E97-4A6E-BCF2-86ABA65E19B2} = {E0414AFD-FC74-438B-8A76-5629421AFEBA}
+ {DED5D1B6-9410-4505-99EF-EC0E935FFE3C} = {AF872388-3655-45E5-9A48-849A50D0C90F}
+ {97961B06-5204-49E1-B49A-FCB79D9711ED} = {AF872388-3655-45E5-9A48-849A50D0C90F}
+ {95347922-E7BA-4D46-8B9E-2FA9DC414795} = {C65054D9-CAD1-4124-B474-D03C178D9D78}
{0833621C-AFB4-4E25-9A4D-7B2E44CA7E05} = {A67D3C5B-2DCD-45B7-BFB6-D019F39C67D9}
{0BFF0671-2B0D-49BE-A583-FE087034AB11} = {9B869A7B-598C-4F67-B962-F00F08920850}
{9B869A7B-598C-4F67-B962-F00F08920850} = {A67D3C5B-2DCD-45B7-BFB6-D019F39C67D9}
@@ -254,6 +327,8 @@ Global
{61A8B896-5E76-411F-951F-4D2BF0344281} = {1614A8B2-CA9A-4F94-B68A-BCC8ED244648}
{9BF030D9-7CBB-458C-8051-E1D7FB9D7E46} = {1614A8B2-CA9A-4F94-B68A-BCC8ED244648}
{ABA2F1E2-B21B-425D-AB54-CC9EF317ADED} = {1614A8B2-CA9A-4F94-B68A-BCC8ED244648}
+ {8972C435-9AB8-4C2A-AB33-A372D731F3DD} = {0D1D2D90-BCFA-47EE-8C72-2E10405F96DF}
+ {691498D2-8DD4-4E04-AEB5-05E8279A57E1} = {8972C435-9AB8-4C2A-AB33-A372D731F3DD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D5378D43-9246-4355-8C4B-880DB15B07DA}
diff --git a/StringExtensions/MintPlayer.StringExtensions/MintPlayer.StringExtensions.csproj b/StringExtensions/MintPlayer.StringExtensions/MintPlayer.StringExtensions.csproj
index 14ccb46e..dbecaf34 100644
--- a/StringExtensions/MintPlayer.StringExtensions/MintPlayer.StringExtensions.csproj
+++ b/StringExtensions/MintPlayer.StringExtensions/MintPlayer.StringExtensions.csproj
@@ -8,7 +8,7 @@
true
true
- 9.0.0
+ 9.1.0
Pieterjan De Clippel
MintPlayer
Generate random strings, string casing extensions, string.Format with placeholder tags
diff --git a/StringExtensions/MintPlayer.StringExtensions/Repeat.cs b/StringExtensions/MintPlayer.StringExtensions/Repeat.cs
new file mode 100644
index 00000000..facf6782
--- /dev/null
+++ b/StringExtensions/MintPlayer.StringExtensions/Repeat.cs
@@ -0,0 +1,10 @@
+namespace MintPlayer.StringExtensions;
+
+public static class RepeatExtensions
+{
+ public static string Repeat(this string text, int count)
+ => string.Join(string.Empty, Enumerable.Range(0, count).Select(_ => text));
+
+ public static string Repeat(this char c, int count)
+ => new string(Enumerable.Range(0, count).Select(_ => c).ToArray());
+}
diff --git a/Verz/ApiHash/MintPlayer.ApiHash/ApiHasher.cs b/Verz/ApiHash/MintPlayer.ApiHash/ApiHasher.cs
new file mode 100644
index 00000000..dabbc712
--- /dev/null
+++ b/Verz/ApiHash/MintPlayer.ApiHash/ApiHasher.cs
@@ -0,0 +1,19 @@
+using System.Security.Cryptography;
+using System.Text;
+using PublicApiGenerator;
+using System.Reflection;
+
+namespace MintPlayer.ApiHash;
+
+public static class ApiHasher
+{
+ public static string ComputeHashFromAssembly(string assemblyPath)
+ {
+ var assembly = Assembly.LoadFrom(assemblyPath);
+ var apiText = ApiGenerator.GeneratePublicApi(assembly);
+ using var sha = SHA256.Create();
+ var bytes = Encoding.UTF8.GetBytes(apiText);
+ var hash = sha.ComputeHash(bytes);
+ return Convert.ToHexString(hash).ToLowerInvariant();
+ }
+}
diff --git a/Verz/ApiHash/MintPlayer.ApiHash/MintPlayer.ApiHash.csproj b/Verz/ApiHash/MintPlayer.ApiHash/MintPlayer.ApiHash.csproj
new file mode 100644
index 00000000..b3115883
--- /dev/null
+++ b/Verz/ApiHash/MintPlayer.ApiHash/MintPlayer.ApiHash.csproj
@@ -0,0 +1,34 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @(ApiHash->'%(Identity)')
+
+
+
+
+
+
+
+
+
+
diff --git a/Verz/MintPlayer.Verz.Abstractions/IDevelopmentSdk.cs b/Verz/MintPlayer.Verz.Abstractions/IDevelopmentSdk.cs
new file mode 100644
index 00000000..1b6fb14b
--- /dev/null
+++ b/Verz/MintPlayer.Verz.Abstractions/IDevelopmentSdk.cs
@@ -0,0 +1,6 @@
+namespace MintPlayer.Verz.Abstractions;
+
+public interface IDevelopmentSdk
+{
+ Task GetPackageById(string packageId);
+}
diff --git a/Verz/MintPlayer.Verz.Abstractions/IPackageRegistry.cs b/Verz/MintPlayer.Verz.Abstractions/IPackageRegistry.cs
new file mode 100644
index 00000000..c5a95ffc
--- /dev/null
+++ b/Verz/MintPlayer.Verz.Abstractions/IPackageRegistry.cs
@@ -0,0 +1,6 @@
+namespace MintPlayer.Verz.Abstractions;
+
+public interface IPackageRegistry
+{
+ Task> GetPackageVersions(string packageId);
+}
diff --git a/Verz/MintPlayer.Verz.Abstractions/MintPlayer.Verz.Abstractions.csproj b/Verz/MintPlayer.Verz.Abstractions/MintPlayer.Verz.Abstractions.csproj
new file mode 100644
index 00000000..3324e6eb
--- /dev/null
+++ b/Verz/MintPlayer.Verz.Abstractions/MintPlayer.Verz.Abstractions.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Verz/MintPlayer.Verz/App.cs b/Verz/MintPlayer.Verz/App.cs
new file mode 100644
index 00000000..170cd2d3
--- /dev/null
+++ b/Verz/MintPlayer.Verz/App.cs
@@ -0,0 +1,255 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using MintPlayer.StringExtensions;
+using MintPlayer.ApiHash;
+using NuGet.Configuration;
+using NuGet.Protocol;
+using NuGet.Protocol.Core.Types;
+using NuGet.Versioning;
+using NuGet.Packaging;
+using System.Reflection;
+using System.Xml.Linq;
+using System.Diagnostics;
+
+namespace MintPlayer.Verz;
+
+internal class App : IApp, IHelper
+{
+ public App() { }
+
+ public async Task Run(string[] args)
+ {
+ if (args.Length >= 2 && args[0].Equals("dotnet", StringComparison.OrdinalIgnoreCase) && args[1].Equals("next", StringComparison.OrdinalIgnoreCase))
+ {
+ await RunDotnetNext(args.Skip(2).ToArray());
+ return;
+ }
+
+ await ShowUsage();
+ }
+
+ public Task ShowUsage()
+ {
+ var versionString = Assembly.GetEntryAssembly()?
+ .GetCustomAttribute()?
+ .InformationalVersion
+ .ToString();
+
+ var versionLine = $"verz v{versionString}";
+
+ Console.WriteLine($"""
+ {versionLine}
+ {"-".Repeat(versionLine.Length)}
+ Usage:
+ verz dotnet next --project [--tfm ] [--nuget-config ]
+ """);
+
+ return Task.CompletedTask;
+ }
+
+ private static (string packageId, string assemblyName, string? tfm, int major) ReadProjectDetails(string csprojPath, string? tfmArg)
+ {
+ var doc = XDocument.Load(csprojPath);
+ XNamespace msbuild = doc.Root!.Name.Namespace;
+ var pg = doc.Root.Elements(msbuild + "PropertyGroup");
+ var packageId = pg.Elements(msbuild + "PackageId").Select(e => e.Value).FirstOrDefault();
+ var assemblyName = pg.Elements(msbuild + "AssemblyName").Select(e => e.Value).FirstOrDefault();
+ var tfm = pg.Elements(msbuild + "TargetFramework").Select(e => e.Value).FirstOrDefault();
+ var tfms = pg.Elements(msbuild + "TargetFrameworks").Select(e => e.Value).FirstOrDefault();
+ if (string.IsNullOrWhiteSpace(packageId)) packageId = Path.GetFileNameWithoutExtension(csprojPath);
+ if (string.IsNullOrWhiteSpace(assemblyName)) assemblyName = packageId;
+
+ string? selectedTfm = tfmArg;
+ if (string.IsNullOrWhiteSpace(selectedTfm))
+ {
+ if (!string.IsNullOrWhiteSpace(tfm)) selectedTfm = tfm;
+ else if (!string.IsNullOrWhiteSpace(tfms))
+ {
+ selectedTfm = tfms.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
+ .OrderByDescending(ParseTfmMajorMinor)
+ .FirstOrDefault();
+ }
+ }
+
+ if (string.IsNullOrWhiteSpace(selectedTfm)) throw new InvalidOperationException("Unable to resolve TargetFramework");
+ var major = ParseTfmMajorMinor(selectedTfm).major;
+ return (packageId!, assemblyName!, selectedTfm, major);
+ }
+
+ private static (int major, int minor) ParseTfmMajorMinor(string tfm)
+ {
+ if (tfm.StartsWith("netstandard"))
+ {
+ var v = tfm.Substring("netstandard".Length);
+ if (Version.TryParse(v, out var stdV)) return (stdV.Major, stdV.Minor);
+ return (2, 0);
+ }
+ if (tfm.StartsWith("net"))
+ {
+ var v = tfm.Substring(3);
+ if (Version.TryParse(v, out var netV)) return (netV.Major, netV.Minor);
+ }
+ return (0, 0);
+ }
+
+ private static async Task BuildProject(string csprojPath, string configuration)
+ {
+ var psi = new ProcessStartInfo("dotnet", $"build \"{csprojPath}\" -c {configuration} --nologo")
+ {
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ WorkingDirectory = Path.GetDirectoryName(csprojPath)!
+ };
+ var p = Process.Start(psi)!;
+ await p.WaitForExitAsync();
+ if (p.ExitCode != 0)
+ {
+ var err = await p.StandardError.ReadToEndAsync();
+ throw new Exception($"Build failed for {csprojPath}: {err}");
+ }
+ }
+
+ private static string GetBuiltAssemblyPath(string csprojPath, string configuration, string tfm, string assemblyName)
+ {
+ var projectDir = Path.GetDirectoryName(csprojPath)!;
+ var dllPath = Path.Combine(projectDir, "bin", configuration, tfm, assemblyName + ".dll");
+ if (!File.Exists(dllPath)) throw new FileNotFoundException("Built assembly not found", dllPath);
+ return dllPath;
+ }
+
+ private static IEnumerable GetPackageSources(string? nugetConfigPath)
+ {
+ ISettings settings;
+ if (!string.IsNullOrWhiteSpace(nugetConfigPath))
+ {
+ var full = Path.GetFullPath(nugetConfigPath);
+ settings = Settings.LoadSpecificSettings(Path.GetDirectoryName(full)!, Path.GetFileName(full));
+ }
+ else
+ {
+ settings = Settings.LoadDefaultSettings(Directory.GetCurrentDirectory());
+ }
+ var provider = new PackageSourceProvider(settings);
+ return provider.LoadPackageSources().Where(s => s.IsEnabled);
+ }
+
+ private static async Task> GetAllPackageVersions(string packageId, IEnumerable sources)
+ {
+ var cache = new SourceCacheContext();
+ var versions = new HashSet();
+ foreach (var source in sources)
+ {
+ var repo = Repository.Factory.GetCoreV3(source);
+ var finder = await repo.GetResourceAsync();
+ var v = await finder.GetAllVersionsAsync(packageId, cache, NuGet.Common.NullLogger.Instance, CancellationToken.None);
+ foreach (var nv in v) versions.Add(nv);
+ }
+ return versions.OrderBy(v => v).ToArray();
+ }
+
+ private static async Task TryDownloadPackageAndComputeApiHash(string packageId, NuGetVersion version, IEnumerable sources, string tfm, string? preferredAssemblyName)
+ {
+ var cache = new SourceCacheContext();
+ foreach (var source in sources)
+ {
+ try
+ {
+ var repo = Repository.Factory.GetCoreV3(source);
+ var finder = await repo.GetResourceAsync();
+ using var mem = new MemoryStream();
+ var ok = await finder.CopyNupkgToStreamAsync(packageId, version, mem, cache, NuGet.Common.NullLogger.Instance, CancellationToken.None);
+ if (!ok) continue;
+ mem.Position = 0;
+ using var reader = new PackageArchiveReader(mem);
+ var refItems = reader.GetFiles($"ref/{tfm}");
+ var libItems = reader.GetFiles($"lib/{tfm}");
+ var dlls = refItems.Concat(libItems).Where(p => p.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)).ToArray();
+ if (dlls.Length == 0) continue;
+ string? pick = null;
+ if (!string.IsNullOrWhiteSpace(preferredAssemblyName))
+ {
+ pick = dlls.FirstOrDefault(p => Path.GetFileNameWithoutExtension(p).Equals(preferredAssemblyName, StringComparison.OrdinalIgnoreCase));
+ }
+ pick ??= dlls.First();
+ using var s = reader.GetStream(pick);
+ var tempDir = Path.Combine(Path.GetTempPath(), "verz", Guid.NewGuid().ToString("N"));
+ Directory.CreateDirectory(tempDir);
+ var tempDll = Path.Combine(tempDir, Path.GetFileName(pick));
+ using (var fs = File.Create(tempDll))
+ {
+ await s.CopyToAsync(fs);
+ }
+ try
+ {
+ return ApiHasher.ComputeHashFromAssembly(tempDll);
+ }
+ finally
+ {
+ try { Directory.Delete(tempDir, true); } catch { }
+ }
+ }
+ catch
+ {
+ // try next source
+ }
+ }
+ return null;
+ }
+
+ private async Task RunDotnetNext(string[] args)
+ {
+ string? csproj = null;
+ string? tfm = null;
+ string? nugetConfig = null;
+ for (int i = 0; i < args.Length; i++)
+ {
+ switch (args[i])
+ {
+ case "--project":
+ csproj = args[++i];
+ break;
+ case "--tfm":
+ tfm = args[++i];
+ break;
+ case "--nuget-config":
+ nugetConfig = args[++i];
+ break;
+ }
+ }
+ if (string.IsNullOrWhiteSpace(csproj) || !File.Exists(csproj)) throw new FileNotFoundException("Project file not found", csproj);
+
+ var (packageId, assemblyName, resolvedTfm, tfmMajor) = ReadProjectDetails(csproj, tfm);
+
+ await BuildProject(csproj, "Release");
+ var assemblyPath = GetBuiltAssemblyPath(csproj, "Release", resolvedTfm!, assemblyName);
+ var currentApiHash = ApiHasher.ComputeHashFromAssembly(assemblyPath);
+
+ var sources = GetPackageSources(nugetConfig).ToArray();
+ var versions = await GetAllPackageVersions(packageId, sources);
+ var bandVersions = versions.Where(v => v.Major == tfmMajor && string.IsNullOrEmpty(v.Release)).ToArray();
+ if (bandVersions.Length == 0)
+ {
+ Console.WriteLine($"{tfmMajor}.0.0");
+ return;
+ }
+
+ var latest = bandVersions.Max();
+ var previousHash = await TryDownloadPackageAndComputeApiHash(packageId, latest, sources, resolvedTfm!, assemblyName);
+ if (previousHash == null)
+ {
+ Console.WriteLine($"{latest.Major}.{latest.Minor}.{latest.Patch + 1}");
+ return;
+ }
+
+ if (string.Equals(previousHash, currentApiHash, StringComparison.Ordinal))
+ {
+ Console.WriteLine($"{latest.Major}.{latest.Minor}.{latest.Patch + 1}");
+ }
+ else
+ {
+ Console.WriteLine($"{latest.Major}.{latest.Minor + 1}.0");
+ }
+ }
+}
diff --git a/Verz/MintPlayer.Verz/MintPlayer.Verz.csproj b/Verz/MintPlayer.Verz/MintPlayer.Verz.csproj
index fbf411ef..3e75ed84 100644
--- a/Verz/MintPlayer.Verz/MintPlayer.Verz.csproj
+++ b/Verz/MintPlayer.Verz/MintPlayer.Verz.csproj
@@ -2,7 +2,8 @@
Exe
- net6.0;net8.0;net9.0
+ net9.0
+ 13
enable
enable
0.0.1
@@ -12,6 +13,26 @@
true
verz
+ 1d1306ff-f7b1-4dab-bea1-99d2d582db9f
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Verz/MintPlayer.Verz/Program.cs b/Verz/MintPlayer.Verz/Program.cs
index 33986699..8afc20ad 100644
--- a/Verz/MintPlayer.Verz/Program.cs
+++ b/Verz/MintPlayer.Verz/Program.cs
@@ -1,2 +1,66 @@
// dotnet tool install --global MintPlayer.Verz
-Console.WriteLine("Hello, World!");
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Hosting.Internal;
+using MintPlayer.Verz;
+
+var app = Host.CreateDefaultBuilder()
+ .ConfigureAppConfiguration((context, config) => { })
+ .ConfigureServices((context, services) =>
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+
+ services
+ .AddNugetOrgRegistry()
+ .AddNpmjsComRegistry()
+ .AddGithubPackageRegistry("MintPlayer", context.Configuration.GetValue("GithubPAT")!)
+ ;
+ services
+ .AddDotnetSDK()
+ .AddNodejsSDK();
+ })
+ .Build();
+
+var runner = app.Services.GetRequiredService();
+var helper = app.Services.GetRequiredService();
+if (args.Length is 1 && args[0] is "--help")
+{
+ await helper.ShowUsage();
+ return;
+}
+
+#if DEBUG
+await runner.Run(args);
+#else
+try
+{
+ await runner.Run(args);
+}
+catch (Exception ex)
+{
+ await helper.ShowUsage();
+}
+#endif
+
+internal interface IApp
+{
+ Task Run(string[] args);
+}
+
+internal interface IHelper
+{
+ Task ShowUsage();
+}
+
+//public interface IAllDotnetPackageSources
+//{
+
+//}
+
+//internal class AllDotnetPackageSources : IAllDotnetPackageSources
+//{
+
+//}
diff --git a/Verz/MintPlayer.Verz/Properties/launchSettings.json b/Verz/MintPlayer.Verz/Properties/launchSettings.json
new file mode 100644
index 00000000..4288c4ae
--- /dev/null
+++ b/Verz/MintPlayer.Verz/Properties/launchSettings.json
@@ -0,0 +1,10 @@
+{
+ "profiles": {
+ "MintPlayer.Verz": {
+ "commandName": "Project",
+ "environmentVariables": {
+ "DOTNET_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/Extensions.cs b/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/Extensions.cs
new file mode 100644
index 00000000..4815469b
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/Extensions.cs
@@ -0,0 +1,17 @@
+using Microsoft.Extensions.DependencyInjection;
+using MintPlayer.Verz.Abstractions;
+using MintPlayer.Verz.Registry.GithubPackageRegistry;
+using MintPlayer.Verz.Sdk.Dotnet.Abstractions;
+using MintPlayer.Verz.Sdk.Nodejs.Abstractions;
+
+namespace MintPlayer.Verz;
+
+public static class Extensions
+{
+ public static IServiceCollection AddGithubPackageRegistry(this IServiceCollection services, string organization, string token)
+ => services
+ .AddSingleton(provider => new GithubPackageRegistry(organization, token))
+ .AddSingleton(provider => provider.GetRequiredService())
+ .AddSingleton(provider => provider.GetRequiredService())
+ .AddSingleton(provider => provider.GetRequiredService());
+}
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/GithubPackageRegistry.cs b/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/GithubPackageRegistry.cs
new file mode 100644
index 00000000..8b2c0021
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/GithubPackageRegistry.cs
@@ -0,0 +1,51 @@
+using MintPlayer.Verz.Abstractions;
+using MintPlayer.Verz.Sdk.Dotnet.Abstractions;
+using MintPlayer.Verz.Sdk.Nodejs.Abstractions;
+using NuGet.Configuration;
+using NuGet.Protocol;
+using NuGet.Protocol.Core.Types;
+using System.Diagnostics.CodeAnalysis;
+
+namespace MintPlayer.Verz.Registry.GithubPackageRegistry;
+
+internal interface IGithubPackageRegistry : IFeedSupportsDotnetSDK, IFeedSupportsNodejsSDK { }
+
+internal class GithubPackageRegistry : IGithubPackageRegistry
+{
+ private readonly string organization;
+ private readonly string token;
+ private SourceCacheContext? cache;
+ private FindPackageByIdResource? nugetPackageFinder;
+ public GithubPackageRegistry(string organization, string token)
+ {
+ this.organization = organization;
+ this.token = token;
+ }
+
+ // https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-nuget-registry
+ public string NugetFeedUrl => $"https://nuget.pkg.github.com/{organization}/index.json";
+
+ // https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry
+ public string NpmFeed => "https://npm.pkg.github.com";
+
+ public async Task> GetPackageVersions(string packageId)
+ {
+ if (nugetPackageFinder == null)
+ await InitializeFeed();
+
+ var packageVersions = await nugetPackageFinder.GetAllVersionsAsync(packageId, cache, NuGet.Common.NullLogger.Instance, CancellationToken.None);
+ return packageVersions.Select(v => string.IsNullOrEmpty(v.Release)
+ ? v.ToString()
+ : $"{v.Version}-{v.Release}");
+ }
+
+ [MemberNotNull(nameof(nugetPackageFinder))]
+ public async Task InitializeFeed()
+ {
+ var feed = new PackageSource(NugetFeedUrl, "github.com");
+ feed.Credentials = new PackageSourceCredential("github.com", organization, token, true, null); // goto github.com/settings/tokens
+ var repository = Repository.Factory.GetCoreV3(feed);
+ nugetPackageFinder = await repository.GetResourceAsync();
+ cache = new SourceCacheContext();
+ }
+}
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/MintPlayer.Verz.Registry.GithubPackageRegistry.csproj b/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/MintPlayer.Verz.Registry.GithubPackageRegistry.csproj
new file mode 100644
index 00000000..d171fc9d
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.GithubPackageRegistry/MintPlayer.Verz.Registry.GithubPackageRegistry.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/Extensions.cs b/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/Extensions.cs
new file mode 100644
index 00000000..79d219fb
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/Extensions.cs
@@ -0,0 +1,15 @@
+using Microsoft.Extensions.DependencyInjection;
+using MintPlayer.Verz.Abstractions;
+using MintPlayer.Verz.Registry.NpmjsCom;
+using MintPlayer.Verz.Sdk.Nodejs.Abstractions;
+
+namespace MintPlayer.Verz;
+
+public static class Extensions
+{
+ public static IServiceCollection AddNpmjsComRegistry(this IServiceCollection services)
+ => services
+ .AddSingleton()
+ .AddSingleton(provider => provider.GetRequiredService())
+ .AddSingleton(provider => provider.GetRequiredService());
+}
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/MintPlayer.Verz.Registry.NpmjsCom.csproj b/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/MintPlayer.Verz.Registry.NpmjsCom.csproj
new file mode 100644
index 00000000..17c2ad7b
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/MintPlayer.Verz.Registry.NpmjsCom.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/NpmjsComPackageRegistry.cs b/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/NpmjsComPackageRegistry.cs
new file mode 100644
index 00000000..5b7b17c0
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.NpmjsCom/NpmjsComPackageRegistry.cs
@@ -0,0 +1,16 @@
+using MintPlayer.Verz.Abstractions;
+using MintPlayer.Verz.Sdk.Nodejs.Abstractions;
+
+namespace MintPlayer.Verz.Registry.NpmjsCom;
+
+internal interface INpmjsComPackageRegistry : IPackageRegistry, IFeedSupportsNodejsSDK { }
+
+internal class NpmjsComPackageRegistry : INpmjsComPackageRegistry
+{
+ public string NpmFeed => "https://registry.npmjs.org";
+
+ public Task> GetPackageVersions(string packageId)
+ {
+ return Task.FromResult>([]);
+ }
+}
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/Extensions.cs b/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/Extensions.cs
new file mode 100644
index 00000000..85e4678a
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/Extensions.cs
@@ -0,0 +1,15 @@
+using Microsoft.Extensions.DependencyInjection;
+using MintPlayer.Verz.Abstractions;
+using MintPlayer.Verz.Registry.NugetOrg;
+using MintPlayer.Verz.Sdk.Dotnet.Abstractions;
+
+namespace MintPlayer.Verz;
+
+public static class Extensions
+{
+ public static IServiceCollection AddNugetOrgRegistry(this IServiceCollection services)
+ => services
+ .AddSingleton()
+ .AddSingleton(provider => provider.GetRequiredService())
+ .AddSingleton(provider => provider.GetRequiredService());
+}
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/MintPlayer.Verz.Registry.NugetOrg.csproj b/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/MintPlayer.Verz.Registry.NugetOrg.csproj
new file mode 100644
index 00000000..2a0704ab
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/MintPlayer.Verz.Registry.NugetOrg.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/NugetOrgPackageRegistry.cs b/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/NugetOrgPackageRegistry.cs
new file mode 100644
index 00000000..3bec599f
--- /dev/null
+++ b/Verz/Registries/MintPlayer.Verz.Registry.NugetOrg/NugetOrgPackageRegistry.cs
@@ -0,0 +1,36 @@
+using MintPlayer.Verz.Abstractions;
+using MintPlayer.Verz.Sdk.Dotnet.Abstractions;
+using NuGet.Configuration;
+using NuGet.Protocol;
+using NuGet.Protocol.Core.Types;
+
+namespace MintPlayer.Verz.Registry.NugetOrg;
+
+internal interface INugetOrgPackageRegistry : IFeedSupportsDotnetSDK { }
+
+internal class NugetOrgPackageRegistry : INugetOrgPackageRegistry
+{
+ private FindPackageByIdResource? nugetPackageFinder;
+ private SourceCacheContext? cache;
+
+ public string NugetFeedUrl => "https://api.nuget.org/v3/index.json";
+
+ public async Task> GetPackageVersions(string packageId)
+ {
+ if (nugetPackageFinder == null)
+ await InitializeFeed();
+
+ var packageVersions = await nugetPackageFinder.GetAllVersionsAsync(packageId, cache, NuGet.Common.NullLogger.Instance, CancellationToken.None);
+ return packageVersions.Select(v => string.IsNullOrEmpty(v.Release)
+ ? v.ToString()
+ : $"{v.Version}-{v.Release}");
+ }
+
+ public async Task InitializeFeed()
+ {
+ var feed = new PackageSource(NugetFeedUrl, "nuget.org");
+ var repository = Repository.Factory.GetCoreV3(feed);
+ nugetPackageFinder = await repository.GetResourceAsync();
+ cache = new SourceCacheContext();
+ }
+}
\ No newline at end of file
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet.Abstractions/IFeedSupportsDotnetSDK.cs b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet.Abstractions/IFeedSupportsDotnetSDK.cs
new file mode 100644
index 00000000..b32796ff
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet.Abstractions/IFeedSupportsDotnetSDK.cs
@@ -0,0 +1,9 @@
+using MintPlayer.Verz.Abstractions;
+
+namespace MintPlayer.Verz.Sdk.Dotnet.Abstractions;
+
+public interface IFeedSupportsDotnetSDK : IPackageRegistry
+{
+ string NugetFeedUrl { get; }
+ Task InitializeFeed();
+}
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet.Abstractions/MintPlayer.Verz.Sdk.Dotnet.Abstractions.csproj b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet.Abstractions/MintPlayer.Verz.Sdk.Dotnet.Abstractions.csproj
new file mode 100644
index 00000000..1148782e
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet.Abstractions/MintPlayer.Verz.Sdk.Dotnet.Abstractions.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/DotnetSDK.cs b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/DotnetSDK.cs
new file mode 100644
index 00000000..2d945ed1
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/DotnetSDK.cs
@@ -0,0 +1,19 @@
+using MintPlayer.Verz.Abstractions;
+using MintPlayer.Verz.Sdk.Dotnet.Abstractions;
+
+namespace MintPlayer.Verz.Sdk.Dotnet;
+
+internal class DotnetSDK : IDevelopmentSdk
+{
+ private readonly IEnumerable dotnetFeeds;
+ public DotnetSDK(IEnumerable dotnetFeeds)
+ {
+ this.dotnetFeeds = dotnetFeeds;
+ }
+
+ public Task GetPackageById(string packageId)
+ {
+ throw new NotImplementedException();
+ //dotnetFeeds.Select(feed => feed.NugetFeedUrl)
+ }
+}
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/Extensions.cs b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/Extensions.cs
new file mode 100644
index 00000000..bbe4da99
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/Extensions.cs
@@ -0,0 +1,11 @@
+using Microsoft.Extensions.DependencyInjection;
+using MintPlayer.Verz.Abstractions;
+using MintPlayer.Verz.Sdk.Dotnet;
+
+namespace MintPlayer.Verz;
+
+public static class Extensions
+{
+ public static IServiceCollection AddDotnetSDK(this IServiceCollection services)
+ => services.AddSingleton();
+}
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/MintPlayer.Verz.Sdk.Dotnet.csproj b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/MintPlayer.Verz.Sdk.Dotnet.csproj
new file mode 100644
index 00000000..3af5e10b
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Dotnet/MintPlayer.Verz.Sdk.Dotnet.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs.Abstractions/IFeedSupportsNodejsSDK.cs b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs.Abstractions/IFeedSupportsNodejsSDK.cs
new file mode 100644
index 00000000..ece156fe
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs.Abstractions/IFeedSupportsNodejsSDK.cs
@@ -0,0 +1,8 @@
+using MintPlayer.Verz.Abstractions;
+
+namespace MintPlayer.Verz.Sdk.Nodejs.Abstractions;
+
+public interface IFeedSupportsNodejsSDK : IPackageRegistry
+{
+ string NpmFeed { get; }
+}
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs.Abstractions/MintPlayer.Verz.Sdk.Nodejs.Abstractions.csproj b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs.Abstractions/MintPlayer.Verz.Sdk.Nodejs.Abstractions.csproj
new file mode 100644
index 00000000..828b849e
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs.Abstractions/MintPlayer.Verz.Sdk.Nodejs.Abstractions.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/Extensions.cs b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/Extensions.cs
new file mode 100644
index 00000000..b9d899ed
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/Extensions.cs
@@ -0,0 +1,11 @@
+using Microsoft.Extensions.DependencyInjection;
+using MintPlayer.Verz.Sdk.Nodejs;
+using MintPlayer.Verz.Abstractions;
+
+namespace MintPlayer.Verz;
+
+public static class Extensions
+{
+ public static IServiceCollection AddNodejsSDK(this IServiceCollection services)
+ => services.AddSingleton();
+}
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/MintPlayer.Verz.Sdk.Nodejs.csproj b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/MintPlayer.Verz.Sdk.Nodejs.csproj
new file mode 100644
index 00000000..21f25cfd
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/MintPlayer.Verz.Sdk.Nodejs.csproj
@@ -0,0 +1,17 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/NodejsSDK.cs b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/NodejsSDK.cs
new file mode 100644
index 00000000..cc0c5423
--- /dev/null
+++ b/Verz/Sdks/MintPlayer.Verz.Sdk.Nodejs/NodejsSDK.cs
@@ -0,0 +1,11 @@
+using MintPlayer.Verz.Abstractions;
+
+namespace MintPlayer.Verz.Sdk.Nodejs;
+
+internal class NodejsSDK : IDevelopmentSdk
+{
+ public Task GetPackageById(string packageId)
+ {
+ throw new NotImplementedException();
+ }
+}