diff --git a/NuGet.config b/NuGet.config index 61a7c1b08c..d0a37a8d8e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,5 +1,4 @@ - diff --git a/eng/PatchConfig.props b/eng/PatchConfig.props index c31e71c5e4..4bb8a4afea 100644 --- a/eng/PatchConfig.props +++ b/eng/PatchConfig.props @@ -65,6 +65,7 @@ Later on, this will be checked using this condition: + Microsoft.AspNetCore.Hosting; diff --git a/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs b/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs index d56360f9aa..a2feb9c39c 100644 --- a/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs +++ b/src/Components/Blazor/Blazor/ref/Microsoft.AspNetCore.Blazor.netstandard2.0.cs @@ -65,16 +65,10 @@ namespace Microsoft.AspNetCore.Blazor.Http } namespace Microsoft.AspNetCore.Blazor.Rendering { - public partial class WebAssemblyRenderer : Microsoft.AspNetCore.Components.Rendering.Renderer + public static partial class WebAssemblyEventDispatcher { - public WebAssemblyRenderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base (default(System.IServiceProvider), default(Microsoft.Extensions.Logging.ILoggerFactory)) { } - public override Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get { throw null; } } - public System.Threading.Tasks.Task AddComponentAsync(System.Type componentType, string domElementSelector) { throw null; } - public System.Threading.Tasks.Task AddComponentAsync(string domElementSelector) where TComponent : Microsoft.AspNetCore.Components.IComponent { throw null; } - public override System.Threading.Tasks.Task DispatchEventAsync(ulong eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo eventFieldInfo, System.EventArgs eventArgs) { throw null; } - protected override void Dispose(bool disposing) { } - protected override void HandleException(System.Exception exception) { } - protected override System.Threading.Tasks.Task UpdateDisplayAsync(in Microsoft.AspNetCore.Components.Rendering.RenderBatch batch) { throw null; } + [Microsoft.JSInterop.JSInvokableAttribute("DispatchEvent")] + public static System.Threading.Tasks.Task DispatchEvent(Microsoft.AspNetCore.Components.Web.WebEventDescriptor eventDescriptor, string eventArgsJson) { throw null; } } } namespace Microsoft.AspNetCore.Components.Builder diff --git a/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj b/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj index 1a0e49e112..c571f776f0 100644 --- a/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj +++ b/src/Components/Blazor/Blazor/src/Microsoft.AspNetCore.Blazor.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -11,4 +11,10 @@ + + + + + + diff --git a/src/Components/Blazor/Blazor/src/Rendering/RendererRegistry.cs b/src/Components/Blazor/Blazor/src/Rendering/RendererRegistry.cs new file mode 100644 index 0000000000..c0f1f98e29 --- /dev/null +++ b/src/Components/Blazor/Blazor/src/Rendering/RendererRegistry.cs @@ -0,0 +1,46 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNetCore.Blazor.Rendering +{ + internal static class RendererRegistry + { + // In case there are multiple concurrent Blazor renderers in the same .NET WebAssembly + // process, we track them by ID. This allows events to be dispatched to the correct one, + // as well as rooting them for GC purposes, since nothing would otherwise be referencing + // them even though we might still receive incoming events from JS. + + private static int _nextId; + private static Dictionary _renderers = new Dictionary(); + + internal static WebAssemblyRenderer Find(int rendererId) + { + return _renderers.ContainsKey(rendererId) + ? _renderers[rendererId] + : throw new ArgumentException($"There is no renderer with ID {rendererId}."); + } + + public static int Add(WebAssemblyRenderer renderer) + { + var id = _nextId++; + _renderers.Add(id, renderer); + return id; + } + + public static bool TryRemove(int rendererId) + { + if (_renderers.ContainsKey(rendererId)) + { + _renderers.Remove(rendererId); + return true; + } + else + { + return false; + } + } + } +} diff --git a/src/Components/Blazor/Blazor/src/Rendering/WebAssemblyEventDispatcher.cs b/src/Components/Blazor/Blazor/src/Rendering/WebAssemblyEventDispatcher.cs new file mode 100644 index 0000000000..d46500bae7 --- /dev/null +++ b/src/Components/Blazor/Blazor/src/Rendering/WebAssemblyEventDispatcher.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.JSInterop; + +namespace Microsoft.AspNetCore.Blazor.Rendering +{ + /// + /// Dispatches events from JavaScript to a Blazor WebAssembly renderer. + /// Intended for internal use only. + /// + public static class WebAssemblyEventDispatcher + { + /// + /// For framework use only. + /// + [JSInvokable(nameof(DispatchEvent))] + public static Task DispatchEvent(WebEventDescriptor eventDescriptor, string eventArgsJson) + { + var webEvent = WebEventData.Parse(eventDescriptor, eventArgsJson); + var renderer = RendererRegistry.Find(eventDescriptor.BrowserRendererId); + return renderer.DispatchEventAsync( + webEvent.EventHandlerId, + webEvent.EventFieldInfo, + webEvent.EventArgs); + } + } +} diff --git a/src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs b/src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs index d4e867621e..5964637090 100644 --- a/src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs +++ b/src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Blazor.Services; using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Rendering; using Microsoft.Extensions.Logging; @@ -16,7 +15,7 @@ namespace Microsoft.AspNetCore.Blazor.Rendering /// Provides mechanisms for rendering instances in a /// web browser, dispatching events to them, and refreshing the UI as required. /// - public class WebAssemblyRenderer : Renderer + internal class WebAssemblyRenderer : Renderer { private readonly int _webAssemblyRendererId; @@ -31,10 +30,8 @@ namespace Microsoft.AspNetCore.Blazor.Rendering public WebAssemblyRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : base(serviceProvider, loggerFactory) { - // The browser renderer registers and unregisters itself with the static - // registry. This works well with the WebAssembly runtime, and is simple for the - // case where Blazor is running in process. - _webAssemblyRendererId = RendererRegistry.Current.Add(this); + // The WebAssembly renderer registers and unregisters itself with the static registry + _webAssemblyRendererId = RendererRegistry.Add(this); } public override Dispatcher Dispatcher => NullDispatcher.Instance; @@ -77,9 +74,9 @@ namespace Microsoft.AspNetCore.Blazor.Rendering WebAssemblyJSRuntime.Instance.Invoke( "Blazor._internal.attachRootComponentToElement", - _webAssemblyRendererId, domElementSelector, - componentId); + componentId, + _webAssemblyRendererId); return RenderRootComponentAsync(componentId); } @@ -88,7 +85,7 @@ namespace Microsoft.AspNetCore.Blazor.Rendering protected override void Dispose(bool disposing) { base.Dispose(disposing); - RendererRegistry.Current.TryRemove(_webAssemblyRendererId); + RendererRegistry.TryRemove(_webAssemblyRendererId); } /// diff --git a/src/Components/Blazor/Templates/src/content/BlazorWasm-CSharp/Client/Shared/SurveyPrompt.razor b/src/Components/Blazor/Templates/src/content/BlazorWasm-CSharp/Client/Shared/SurveyPrompt.razor index 5baad704a9..d392ed3eeb 100644 --- a/src/Components/Blazor/Templates/src/content/BlazorWasm-CSharp/Client/Shared/SurveyPrompt.razor +++ b/src/Components/Blazor/Templates/src/content/BlazorWasm-CSharp/Client/Shared/SurveyPrompt.razor @@ -4,7 +4,7 @@ Please take our - brief survey + brief survey and tell us what you think. diff --git a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs index 68325c4ec0..e3d29e6a52 100644 --- a/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs +++ b/src/Components/Components/ref/Microsoft.AspNetCore.Components.netstandard2.0.cs @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Components public CascadingParameterAttribute() { } public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } } - public partial class CascadingValue : Microsoft.AspNetCore.Components.IComponent + public partial class CascadingValue : Microsoft.AspNetCore.Components.IComponent { public CascadingValue() { } [Microsoft.AspNetCore.Components.ParameterAttribute] @@ -124,7 +124,7 @@ namespace Microsoft.AspNetCore.Components [Microsoft.AspNetCore.Components.ParameterAttribute] public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } [Microsoft.AspNetCore.Components.ParameterAttribute] - public T Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public TValue Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public void Attach(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { } public System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } } @@ -188,17 +188,17 @@ namespace Microsoft.AspNetCore.Components public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback CreateInferred(object receiver, System.Action callback, T value) { throw null; } + public Microsoft.AspNetCore.Components.EventCallback CreateInferred(object receiver, System.Action callback, TValue value) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback CreateInferred(object receiver, System.Func callback, T value) { throw null; } + public Microsoft.AspNetCore.Components.EventCallback CreateInferred(object receiver, System.Func callback, TValue value) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } + public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } - public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } + public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; } + public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } + public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; } + public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } + public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func callback) { throw null; } } public static partial class EventCallbackFactoryBinderExtensions { @@ -241,13 +241,13 @@ namespace Microsoft.AspNetCore.Components public System.Threading.Tasks.Task InvokeAsync(object arg) { throw null; } } [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct EventCallback + public readonly partial struct EventCallback { private readonly object _dummy; - public static readonly Microsoft.AspNetCore.Components.EventCallback Empty; + public static readonly Microsoft.AspNetCore.Components.EventCallback Empty; public EventCallback(Microsoft.AspNetCore.Components.IHandleEvent receiver, System.MulticastDelegate @delegate) { throw null; } public bool HasDelegate { get { throw null; } } - public System.Threading.Tasks.Task InvokeAsync(T arg) { throw null; } + public System.Threading.Tasks.Task InvokeAsync(TValue arg) { throw null; } } public partial interface IComponent { @@ -365,11 +365,11 @@ namespace Microsoft.AspNetCore.Components public static Microsoft.AspNetCore.Components.ParameterView Empty { get { throw null; } } public static Microsoft.AspNetCore.Components.ParameterView FromDictionary(System.Collections.Generic.IDictionary parameters) { throw null; } public Microsoft.AspNetCore.Components.ParameterView.Enumerator GetEnumerator() { throw null; } - public T GetValueOrDefault(string parameterName) { throw null; } - public T GetValueOrDefault(string parameterName, T defaultValue) { throw null; } + public TValue GetValueOrDefault(string parameterName) { throw null; } + public TValue GetValueOrDefault(string parameterName, TValue defaultValue) { throw null; } public void SetParameterProperties(object target) { } public System.Collections.Generic.IReadOnlyDictionary ToDictionary() { throw null; } - public bool TryGetValue(string parameterName, out T result) { throw null; } + public bool TryGetValue(string parameterName, out TValue result) { throw null; } [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public partial struct Enumerator { @@ -380,7 +380,7 @@ namespace Microsoft.AspNetCore.Components } } public delegate void RenderFragment(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder); - public delegate Microsoft.AspNetCore.Components.RenderFragment RenderFragment(T value); + public delegate Microsoft.AspNetCore.Components.RenderFragment RenderFragment(TValue value); [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public readonly partial struct RenderHandle { @@ -466,7 +466,7 @@ namespace Microsoft.AspNetCore.Components.Forms public FieldIdentifier(object model, string fieldName) { throw null; } public string FieldName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } public object Model { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public static Microsoft.AspNetCore.Components.Forms.FieldIdentifier Create(System.Linq.Expressions.Expression> accessor) { throw null; } + public static Microsoft.AspNetCore.Components.Forms.FieldIdentifier Create(System.Linq.Expressions.Expression> accessor) { throw null; } public bool Equals(Microsoft.AspNetCore.Components.Forms.FieldIdentifier otherIdentifier) { throw null; } public override bool Equals(object obj) { throw null; } public override int GetHashCode() { throw null; } @@ -556,13 +556,13 @@ namespace Microsoft.AspNetCore.Components.Rendering public void AddAttribute(int sequence, string name, System.MulticastDelegate value) { } public void AddAttribute(int sequence, string name, object value) { } public void AddAttribute(int sequence, string name, string value) { } - public void AddAttribute(int sequence, string name, Microsoft.AspNetCore.Components.EventCallback value) { } + public void AddAttribute(int sequence, string name, Microsoft.AspNetCore.Components.EventCallback value) { } public void AddComponentReferenceCapture(int sequence, System.Action componentReferenceCaptureAction) { } public void AddContent(int sequence, Microsoft.AspNetCore.Components.MarkupString markupContent) { } public void AddContent(int sequence, Microsoft.AspNetCore.Components.RenderFragment fragment) { } public void AddContent(int sequence, object textContent) { } public void AddContent(int sequence, string textContent) { } - public void AddContent(int sequence, Microsoft.AspNetCore.Components.RenderFragment fragment, T value) { } + public void AddContent(int sequence, Microsoft.AspNetCore.Components.RenderFragment fragment, TValue value) { } public void AddElementReferenceCapture(int sequence, System.Action elementReferenceCaptureAction) { } public void AddMarkupContent(int sequence, string markupContent) { } public void AddMultipleAttributes(int sequence, System.Collections.Generic.IEnumerable> attributes) { } diff --git a/src/Components/Components/src/Auth/CascadingAuthenticationState.razor b/src/Components/Components/src/Auth/CascadingAuthenticationState.razor index 4f2e2bd630..695ebd1972 100644 --- a/src/Components/Components/src/Auth/CascadingAuthenticationState.razor +++ b/src/Components/Components/src/Auth/CascadingAuthenticationState.razor @@ -2,7 +2,7 @@ @implements IDisposable @inject AuthenticationStateProvider AuthenticationStateProvider - + @code { private Task _currentAuthenticationStateTask; diff --git a/src/Components/Components/src/CascadingValue.cs b/src/Components/Components/src/CascadingValue.cs index 1a03c2557e..564ca99def 100644 --- a/src/Components/Components/src/CascadingValue.cs +++ b/src/Components/Components/src/CascadingValue.cs @@ -5,14 +5,13 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components.RenderTree; namespace Microsoft.AspNetCore.Components { /// /// A component that provides a cascading value to all descendant components. /// - public class CascadingValue : ICascadingValueComponent, IComponent + public class CascadingValue : ICascadingValueComponent, IComponent { private RenderHandle _renderHandle; private HashSet _subscribers; // Lazily instantiated @@ -26,7 +25,7 @@ namespace Microsoft.AspNetCore.Components /// /// The value to be provided. /// - [Parameter] public T Value { get; set; } + [Parameter] public TValue Value { get; set; } /// /// Optionally gives a name to the provided value. Descendant components @@ -74,7 +73,7 @@ namespace Microsoft.AspNetCore.Components { if (parameter.Name.Equals(nameof(Value), StringComparison.OrdinalIgnoreCase)) { - Value = (T)parameter.Value; + Value = (TValue)parameter.Value; hasSuppliedValue = true; } else if (parameter.Name.Equals(nameof(ChildContent), StringComparison.OrdinalIgnoreCase)) @@ -86,7 +85,7 @@ namespace Microsoft.AspNetCore.Components Name = (string)parameter.Value; if (string.IsNullOrEmpty(Name)) { - throw new ArgumentException($"The parameter '{nameof(Name)}' for component '{nameof(CascadingValue)}' does not allow null or empty values."); + throw new ArgumentException($"The parameter '{nameof(Name)}' for component '{nameof(CascadingValue)}' does not allow null or empty values."); } } else if (parameter.Name.Equals(nameof(IsFixed), StringComparison.OrdinalIgnoreCase)) @@ -95,7 +94,7 @@ namespace Microsoft.AspNetCore.Components } else { - throw new ArgumentException($"The component '{nameof(CascadingValue)}' does not accept a parameter with the name '{parameter.Name}'."); + throw new ArgumentException($"The component '{nameof(CascadingValue)}' does not accept a parameter with the name '{parameter.Name}'."); } } @@ -136,7 +135,7 @@ namespace Microsoft.AspNetCore.Components bool ICascadingValueComponent.CanSupplyValue(Type requestedType, string requestedName) { - if (!requestedType.IsAssignableFrom(typeof(T))) + if (!requestedType.IsAssignableFrom(typeof(TValue))) { return false; } diff --git a/src/Components/Components/src/EventCallback.cs b/src/Components/Components/src/EventCallback.cs index 0d37124c64..3ba05ceaba 100644 --- a/src/Components/Components/src/EventCallback.cs +++ b/src/Components/Components/src/EventCallback.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Components internal readonly IHandleEvent Receiver; /// - /// Creates the new . + /// Creates the new . /// /// The event receiver. /// The delegate to bind. @@ -66,73 +66,4 @@ namespace Microsoft.AspNetCore.Components return RequiresExplicitReceiver ? (object)this : Delegate; } } - - /// - /// A bound event handler delegate. - /// - public readonly struct EventCallback : IEventCallback - { - /// - /// Gets an empty . - /// - public static readonly EventCallback Empty = new EventCallback(null, (Action)(() => { })); - - internal readonly MulticastDelegate Delegate; - internal readonly IHandleEvent Receiver; - - /// - /// Creates the new . - /// - /// The event receiver. - /// The delegate to bind. - public EventCallback(IHandleEvent receiver, MulticastDelegate @delegate) - { - Receiver = receiver; - Delegate = @delegate; - } - - /// - /// Gets a value that indicates whether the delegate associated with this event dispatcher is non-null. - /// - public bool HasDelegate => Delegate != null; - - // This is a hint to the runtime that Receiver is a different object than what - // Delegate.Target points to. This allows us to avoid boxing the command object - // when building the render tree. See logic where this is used. - internal bool RequiresExplicitReceiver => Receiver != null && !object.ReferenceEquals(Receiver, Delegate?.Target); - - /// - /// Invokes the delegate associated with this binding and dispatches an event notification to the - /// appropriate component. - /// - /// The argument. - /// A which completes asynchronously once event processing has completed. - public Task InvokeAsync(T arg) - { - if (Receiver == null) - { - return EventCallbackWorkItem.InvokeAsync(Delegate, arg); - } - - return Receiver.HandleEventAsync(new EventCallbackWorkItem(Delegate), arg); - } - - internal EventCallback AsUntyped() - { - return new EventCallback(Receiver ?? Delegate?.Target as IHandleEvent, Delegate); - } - - object IEventCallback.UnpackForRenderTree() - { - return RequiresExplicitReceiver ? (object)AsUntyped() : Delegate; - } - } - - // Used to understand boxed generic EventCallbacks - internal interface IEventCallback - { - bool HasDelegate { get; } - - object UnpackForRenderTree(); - } } diff --git a/src/Components/Components/src/EventCallbackFactory.cs b/src/Components/Components/src/EventCallbackFactory.cs index a920d2277d..1b53376b85 100644 --- a/src/Components/Components/src/EventCallbackFactory.cs +++ b/src/Components/Components/src/EventCallbackFactory.cs @@ -105,14 +105,14 @@ namespace Microsoft.AspNetCore.Components /// /// [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback Create(object receiver, EventCallback callback) + public EventCallback Create(object receiver, EventCallback callback) { if (receiver == null) { throw new ArgumentNullException(nameof(receiver)); } - return new EventCallback(callback.Receiver, callback.Delegate); + return new EventCallback(callback.Receiver, callback.Delegate); } /// @@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Components /// /// [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback Create(object receiver, EventCallback callback) + public EventCallback Create(object receiver, EventCallback callback) { if (receiver == null) { @@ -139,14 +139,14 @@ namespace Microsoft.AspNetCore.Components /// The event receiver. /// The event callback. /// The . - public EventCallback Create(object receiver, Action callback) + public EventCallback Create(object receiver, Action callback) { if (receiver == null) { throw new ArgumentNullException(nameof(receiver)); } - return CreateCore(receiver, callback); + return CreateCore(receiver, callback); } /// @@ -156,14 +156,14 @@ namespace Microsoft.AspNetCore.Components /// The event receiver. /// The event callback. /// The . - public EventCallback Create(object receiver, Action callback) + public EventCallback Create(object receiver, Action callback) { if (receiver == null) { throw new ArgumentNullException(nameof(receiver)); } - return CreateCore(receiver, callback); + return CreateCore(receiver, callback); } /// @@ -173,14 +173,14 @@ namespace Microsoft.AspNetCore.Components /// The event receiver. /// The event callback. /// The . - public EventCallback Create(object receiver, Func callback) + public EventCallback Create(object receiver, Func callback) { if (receiver == null) { throw new ArgumentNullException(nameof(receiver)); } - return CreateCore(receiver, callback); + return CreateCore(receiver, callback); } /// @@ -190,14 +190,14 @@ namespace Microsoft.AspNetCore.Components /// The event receiver. /// The event callback. /// The . - public EventCallback Create(object receiver, Func callback) + public EventCallback Create(object receiver, Func callback) { if (receiver == null) { throw new ArgumentNullException(nameof(receiver)); } - return CreateCore(receiver, callback); + return CreateCore(receiver, callback); } /// @@ -209,7 +209,7 @@ namespace Microsoft.AspNetCore.Components /// /// [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback CreateInferred(object receiver, Action callback, T value) + public EventCallback CreateInferred(object receiver, Action callback, TValue value) { return Create(receiver, callback); } @@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Components /// /// [EditorBrowsable(EditorBrowsableState.Never)] - public EventCallback CreateInferred(object receiver, Func callback, T value) + public EventCallback CreateInferred(object receiver, Func callback, TValue value) { return Create(receiver, callback); } @@ -233,9 +233,9 @@ namespace Microsoft.AspNetCore.Components return new EventCallback(callback?.Target as IHandleEvent ?? receiver as IHandleEvent, callback); } - private EventCallback CreateCore(object receiver, MulticastDelegate callback) + private EventCallback CreateCore(object receiver, MulticastDelegate callback) { - return new EventCallback(callback?.Target as IHandleEvent ?? receiver as IHandleEvent, callback); + return new EventCallback(callback?.Target as IHandleEvent ?? receiver as IHandleEvent, callback); } } } diff --git a/src/Components/Components/src/EventCallbackOfT.cs b/src/Components/Components/src/EventCallbackOfT.cs new file mode 100644 index 0000000000..918d8d62e2 --- /dev/null +++ b/src/Components/Components/src/EventCallbackOfT.cs @@ -0,0 +1,69 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Components +{ + /// + /// A bound event handler delegate. + /// + public readonly struct EventCallback : IEventCallback + { + /// + /// Gets an empty . + /// + public static readonly EventCallback Empty = new EventCallback(null, (Action)(() => { })); + + internal readonly MulticastDelegate Delegate; + internal readonly IHandleEvent Receiver; + + /// + /// Creates the new . + /// + /// The event receiver. + /// The delegate to bind. + public EventCallback(IHandleEvent receiver, MulticastDelegate @delegate) + { + Receiver = receiver; + Delegate = @delegate; + } + + /// + /// Gets a value that indicates whether the delegate associated with this event dispatcher is non-null. + /// + public bool HasDelegate => Delegate != null; + + // This is a hint to the runtime that Receiver is a different object than what + // Delegate.Target points to. This allows us to avoid boxing the command object + // when building the render tree. See logic where this is used. + internal bool RequiresExplicitReceiver => Receiver != null && !object.ReferenceEquals(Receiver, Delegate?.Target); + + /// + /// Invokes the delegate associated with this binding and dispatches an event notification to the + /// appropriate component. + /// + /// The argument. + /// A which completes asynchronously once event processing has completed. + public Task InvokeAsync(TValue arg) + { + if (Receiver == null) + { + return EventCallbackWorkItem.InvokeAsync(Delegate, arg); + } + + return Receiver.HandleEventAsync(new EventCallbackWorkItem(Delegate), arg); + } + + internal EventCallback AsUntyped() + { + return new EventCallback(Receiver ?? Delegate?.Target as IHandleEvent, Delegate); + } + + object IEventCallback.UnpackForRenderTree() + { + return RequiresExplicitReceiver ? (object)AsUntyped() : Delegate; + } + } +} diff --git a/src/Components/Components/src/Forms/FieldIdentifier.cs b/src/Components/Components/src/Forms/FieldIdentifier.cs index fa3fb72dad..1c2c923d38 100644 --- a/src/Components/Components/src/Forms/FieldIdentifier.cs +++ b/src/Components/Components/src/Forms/FieldIdentifier.cs @@ -16,7 +16,8 @@ namespace Microsoft.AspNetCore.Components.Forms /// Initializes a new instance of the structure. /// /// An expression that identifies an object member. - public static FieldIdentifier Create(Expression> accessor) + /// The field . + public static FieldIdentifier Create(Expression> accessor) { if (accessor == null) { diff --git a/src/Components/Components/src/IEventCallback.cs b/src/Components/Components/src/IEventCallback.cs new file mode 100644 index 0000000000..6c9fcac7a3 --- /dev/null +++ b/src/Components/Components/src/IEventCallback.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Components +{ + // Used to understand boxed generic EventCallbacks + internal interface IEventCallback + { + bool HasDelegate { get; } + + object UnpackForRenderTree(); + } +} diff --git a/src/Components/Components/src/ParameterView.cs b/src/Components/Components/src/ParameterView.cs index 3d682cc09c..fb7329aab2 100644 --- a/src/Components/Components/src/ParameterView.cs +++ b/src/Components/Components/src/ParameterView.cs @@ -53,17 +53,17 @@ namespace Microsoft.AspNetCore.Components /// /// Gets the value of the parameter with the specified name. /// - /// The type of the value. + /// The type of the value. /// The name of the parameter. /// Receives the result, if any. /// True if a matching parameter was found; false otherwise. - public bool TryGetValue(string parameterName, out T result) + public bool TryGetValue(string parameterName, out TValue result) { foreach (var entry in this) { if (string.Equals(entry.Name, parameterName)) { - result = (T)entry.Value; + result = (TValue)entry.Value; return true; } } @@ -76,22 +76,22 @@ namespace Microsoft.AspNetCore.Components /// Gets the value of the parameter with the specified name, or a default value /// if no such parameter exists in the collection. /// - /// The type of the value. + /// The type of the value. /// The name of the parameter. /// The parameter value if found; otherwise the default value for the specified type. - public T GetValueOrDefault(string parameterName) - => GetValueOrDefault(parameterName, default); + public TValue GetValueOrDefault(string parameterName) + => GetValueOrDefault(parameterName, default); /// /// Gets the value of the parameter with the specified name, or a specified default value /// if no such parameter exists in the collection. /// - /// The type of the value. + /// The type of the value. /// The name of the parameter. /// The default value to return if no such parameter exists in the collection. /// The parameter value if found; otherwise . - public T GetValueOrDefault(string parameterName, T defaultValue) - => TryGetValue(parameterName, out T result) ? result : defaultValue; + public TValue GetValueOrDefault(string parameterName, TValue defaultValue) + => TryGetValue(parameterName, out TValue result) ? result : defaultValue; /// /// Returns a dictionary populated with the contents of the . diff --git a/src/Components/Components/src/RenderFragment.cs b/src/Components/Components/src/RenderFragment.cs index 06b96bfca7..cf27ad2cc4 100644 --- a/src/Components/Components/src/RenderFragment.cs +++ b/src/Components/Components/src/RenderFragment.cs @@ -13,10 +13,10 @@ namespace Microsoft.AspNetCore.Components public delegate void RenderFragment(RenderTreeBuilder builder); /// - /// Represents a segment of UI content for an object of type , implemented as + /// Represents a segment of UI content for an object of type , implemented as /// a function that returns a . /// - /// The type of object. + /// The type of object. /// The value used to build the content. - public delegate RenderFragment RenderFragment(T value); + public delegate RenderFragment RenderFragment(TValue value); } diff --git a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs index 161a274c25..6876c97f0d 100644 --- a/src/Components/Components/src/Rendering/RenderTreeBuilder.cs +++ b/src/Components/Components/src/Rendering/RenderTreeBuilder.cs @@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.Components.Rendering /// An integer that represents the position of the instruction in the source code. /// Content to append. /// The value used by . - public void AddContent(int sequence, RenderFragment fragment, T value) + public void AddContent(int sequence, RenderFragment fragment, TValue value) { if (fragment != null) { @@ -281,7 +281,7 @@ namespace Microsoft.AspNetCore.Components.Rendering /// This method is provided for infrastructure purposes, and is used to support generated code /// that uses . /// - public void AddAttribute(int sequence, string name, EventCallback value) + public void AddAttribute(int sequence, string name, EventCallback value) { AssertCanAddAttribute(); if (_lastNonAttributeFrameType == RenderTreeFrameType.Component) diff --git a/src/Components/Server/src/Circuits/CircuitHost.cs b/src/Components/Server/src/Circuits/CircuitHost.cs index c2a38e25b9..92a2365971 100644 --- a/src/Components/Server/src/Circuits/CircuitHost.cs +++ b/src/Components/Server/src/Circuits/CircuitHost.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Security.Claims; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Web; @@ -41,7 +40,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits } JSInterop.JSRuntime.SetCurrentJSRuntime(circuitHost.JSRuntime); - RendererRegistry.SetCurrentRendererRegistry(circuitHost.RendererRegistry); } public event UnhandledExceptionEventHandler UnhandledException; @@ -50,7 +48,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits string circuitId, IServiceScope scope, CircuitClientProxy client, - RendererRegistry rendererRegistry, RemoteRenderer renderer, IReadOnlyList descriptors, RemoteJSRuntime jsRuntime, @@ -60,7 +57,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits CircuitId = circuitId; _scope = scope ?? throw new ArgumentNullException(nameof(scope)); Client = client; - RendererRegistry = rendererRegistry ?? throw new ArgumentNullException(nameof(rendererRegistry)); Descriptors = descriptors ?? throw new ArgumentNullException(nameof(descriptors)); Renderer = renderer ?? throw new ArgumentNullException(nameof(renderer)); JSRuntime = jsRuntime ?? throw new ArgumentNullException(nameof(jsRuntime)); @@ -85,8 +81,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits public RemoteRenderer Renderer { get; } - public RendererRegistry RendererRegistry { get; } - public IReadOnlyList Descriptors { get; } public IServiceProvider Services { get; } @@ -137,46 +131,38 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits } } - public async Task DispatchEvent(string eventDescriptorJson, string eventArgs) + public async Task DispatchEvent(string eventDescriptorJson, string eventArgsJson) { - RendererRegistryEventDispatcher.BrowserEventDescriptor eventDescriptor = null; + WebEventData webEventData; try { AssertInitialized(); - eventDescriptor = ParseEventDescriptor(eventDescriptorJson); - if (eventDescriptor == null) - { - return; - } + webEventData = WebEventData.Parse(eventDescriptorJson, eventArgsJson); + } + catch (Exception ex) + { + Log.DispatchEventFailedToParseEventData(_logger, ex); + return; + } + try + { await Renderer.Dispatcher.InvokeAsync(() => { SetCurrentCircuitHost(this); - return RendererRegistryEventDispatcher.DispatchEvent(eventDescriptor, eventArgs); + return Renderer.DispatchEventAsync( + webEventData.EventHandlerId, + webEventData.EventFieldInfo, + webEventData.EventArgs); }); } catch (Exception ex) { - Log.DispatchEventFailedToDispatchEvent(_logger, eventDescriptor != null ? eventDescriptor.EventHandlerId.ToString() : null, ex); + Log.DispatchEventFailedToDispatchEvent(_logger, webEventData.EventHandlerId.ToString(), ex); UnhandledException?.Invoke(this, new UnhandledExceptionEventArgs(ex, isTerminating: false)); } } - private RendererRegistryEventDispatcher.BrowserEventDescriptor ParseEventDescriptor(string eventDescriptorJson) - { - try - { - return JsonSerializer.Deserialize( - eventDescriptorJson, - JsonSerializerOptionsProvider.Options); - } - catch (Exception ex) - { - Log.DispatchEventFailedToParseEventDescriptor(_logger, ex); - return null; - } - } - public async Task InitializeAsync(CancellationToken cancellationToken) { await Renderer.Dispatcher.InvokeAsync(async () => @@ -214,11 +200,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits try { AssertInitialized(); - if (assemblyName == "Microsoft.AspNetCore.Components.Web" && methodIdentifier == "DispatchEvent") - { - Log.DispatchEventTroughJSInterop(_logger); - return; - } await Renderer.Dispatcher.InvokeAsync(() => { @@ -410,9 +391,8 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits private static readonly Action _endInvokeDispatchException; private static readonly Action _endInvokeJSFailed; private static readonly Action _endInvokeJSSucceeded; - private static readonly Action _dispatchEventFailedToParseEventDescriptor; + private static readonly Action _dispatchEventFailedToParseEventData; private static readonly Action _dispatchEventFailedToDispatchEvent; - private static readonly Action _dispatchEventThroughJSInterop; private static readonly Action _locationChange; private static readonly Action _locationChangeSucceeded; private static readonly Action _locationChangeFailed; @@ -426,7 +406,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits public static readonly EventId OnConnectionDown = new EventId(104, "OnConnectionDown"); public static readonly EventId OnCircuitClosed = new EventId(105, "OnCircuitClosed"); public static readonly EventId InvalidBrowserEventFormat = new EventId(106, "InvalidBrowserEventFormat"); - public static readonly EventId DispatchEventFailedToParseEventDescriptor = new EventId(107, "DispatchEventFailedToParseEventDescriptor"); + public static readonly EventId DispatchEventFailedToParseEventData = new EventId(107, "DispatchEventFailedToParseEventData"); public static readonly EventId DispatchEventFailedToDispatchEvent = new EventId(108, "DispatchEventFailedToDispatchEvent"); public static readonly EventId BeginInvokeDotNet = new EventId(109, "BeginInvokeDotNet"); public static readonly EventId EndInvokeDispatchException = new EventId(110, "EndInvokeDispatchException"); @@ -495,21 +475,16 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits EventIds.EndInvokeJSSucceeded, "The JS interop call with callback id '{AsyncCall}' succeeded."); - _dispatchEventFailedToParseEventDescriptor = LoggerMessage.Define( + _dispatchEventFailedToParseEventData = LoggerMessage.Define( LogLevel.Debug, - EventIds.DispatchEventFailedToParseEventDescriptor, - "Failed to parse the event descriptor data when trying to dispatch an event."); + EventIds.DispatchEventFailedToParseEventData, + "Failed to parse the event data when trying to dispatch an event."); _dispatchEventFailedToDispatchEvent = LoggerMessage.Define( LogLevel.Debug, EventIds.DispatchEventFailedToDispatchEvent, "There was an error dispatching the event '{EventHandlerId}' to the application."); - _dispatchEventThroughJSInterop = LoggerMessage.Define( - LogLevel.Debug, - EventIds.DispatchEventThroughJSInterop, - "There was an intent to dispatch a browser event through JS interop."); - _locationChange = LoggerMessage.Define( LogLevel.Debug, EventIds.LocationChange, @@ -555,7 +530,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits public static void EndInvokeJSSucceeded(ILogger logger, long asyncCall) => _endInvokeJSSucceeded(logger, asyncCall, null); - public static void DispatchEventFailedToParseEventDescriptor(ILogger logger, Exception ex) => _dispatchEventFailedToParseEventDescriptor(logger, ex); + public static void DispatchEventFailedToParseEventData(ILogger logger, Exception ex) => _dispatchEventFailedToParseEventData(logger, ex); public static void DispatchEventFailedToDispatchEvent(ILogger logger, string eventHandlerId, Exception ex) => _dispatchEventFailedToDispatchEvent(logger, eventHandlerId ?? "", ex); @@ -571,8 +546,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits } } - public static void DispatchEventTroughJSInterop(ILogger logger) => _dispatchEventThroughJSInterop(logger, null); - public static void LocationChange(ILogger logger, string circuitId, string uri) => _locationChange(logger, circuitId, uri, null); public static void LocationChangeSucceeded(ILogger logger, string circuitId, string uri) => _locationChangeSucceeded(logger, circuitId, uri, null); diff --git a/src/Components/Server/src/Circuits/DefaultCircuitFactory.cs b/src/Components/Server/src/Circuits/DefaultCircuitFactory.cs index f3463301b1..43af5cc8f4 100644 --- a/src/Components/Server/src/Circuits/DefaultCircuitFactory.cs +++ b/src/Components/Server/src/Circuits/DefaultCircuitFactory.cs @@ -72,11 +72,9 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits navigationManager.Initialize(baseUri, uri); } - var rendererRegistry = new RendererRegistry(); var renderer = new RemoteRenderer( scope.ServiceProvider, _loggerFactory, - rendererRegistry, _options, jsRuntime, client, @@ -91,7 +89,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits _circuitIdFactory.CreateCircuitId(), scope, client, - rendererRegistry, renderer, components, jsRuntime, diff --git a/src/Components/Server/src/Circuits/RemoteRenderer.cs b/src/Components/Server/src/Circuits/RemoteRenderer.cs index 096ee33ff0..f2dae7dd0d 100644 --- a/src/Components/Server/src/Circuits/RemoteRenderer.cs +++ b/src/Components/Server/src/Circuits/RemoteRenderer.cs @@ -24,7 +24,6 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering private readonly IJSRuntime _jsRuntime; private readonly CircuitClientProxy _client; private readonly CircuitOptions _options; - private readonly RendererRegistry _rendererRegistry; private readonly ILogger _logger; internal readonly ConcurrentQueue _unacknowledgedRenderBatches = new ConcurrentQueue(); private long _nextRenderId = 1; @@ -41,7 +40,6 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering public RemoteRenderer( IServiceProvider serviceProvider, ILoggerFactory loggerFactory, - RendererRegistry rendererRegistry, CircuitOptions options, IJSRuntime jsRuntime, CircuitClientProxy client, @@ -49,19 +47,14 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering ILogger logger) : base(serviceProvider, loggerFactory, encoder.Encode) { - _rendererRegistry = rendererRegistry; _jsRuntime = jsRuntime; _client = client; _options = options; - - Id = _rendererRegistry.Add(this); _logger = logger; } public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault(); - public int Id { get; } - /// /// Associates the with the , /// causing it to be displayed in the specified DOM element. @@ -75,7 +68,6 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering var attachComponentTask = _jsRuntime.InvokeAsync( "Blazor._internal.attachRootComponentToElement", - Id, domElementSelector, componentId); CaptureAsyncExceptions(attachComponentTask); @@ -133,7 +125,6 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering protected override void Dispose(bool disposing) { _disposing = true; - _rendererRegistry.TryRemove(Id); while (_unacknowledgedRenderBatches.TryDequeue(out var entry)) { entry.CompletionSource.TrySetCanceled(); @@ -220,7 +211,7 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering Log.BeginUpdateDisplayAsync(_logger, _client.ConnectionId, pending.BatchId, pending.Data.Count); var segment = new ArraySegment(pending.Data.Buffer, 0, pending.Data.Count); - await _client.SendAsync("JS.RenderBatch", Id, pending.BatchId, segment); + await _client.SendAsync("JS.RenderBatch", pending.BatchId, segment); } catch (Exception e) { diff --git a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj index 35e5a62198..639cdc9d5b 100644 --- a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj +++ b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj @@ -41,6 +41,10 @@ + + + + diff --git a/src/Components/Server/test/Circuits/CircuitHostTest.cs b/src/Components/Server/test/Circuits/CircuitHostTest.cs index a6c78f8683..3c2ca28992 100644 --- a/src/Components/Server/test/Circuits/CircuitHostTest.cs +++ b/src/Components/Server/test/Circuits/CircuitHostTest.cs @@ -232,15 +232,14 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits { return new TestRemoteRenderer( Mock.Of(), - new RendererRegistry(), Mock.Of(), Mock.Of()); } private class TestRemoteRenderer : RemoteRenderer { - public TestRemoteRenderer(IServiceProvider serviceProvider, RendererRegistry rendererRegistry, IJSRuntime jsRuntime, IClientProxy client) - : base(serviceProvider, NullLoggerFactory.Instance, rendererRegistry, new CircuitOptions(), jsRuntime, new CircuitClientProxy(client, "connection"), HtmlEncoder.Default, NullLogger.Instance) + public TestRemoteRenderer(IServiceProvider serviceProvider, IJSRuntime jsRuntime, IClientProxy client) + : base(serviceProvider, NullLoggerFactory.Instance, new CircuitOptions(), jsRuntime, new CircuitClientProxy(client, "connection"), HtmlEncoder.Default, NullLogger.Instance) { } diff --git a/src/Components/Server/test/Circuits/RemoteRendererTest.cs b/src/Components/Server/test/Circuits/RemoteRendererTest.cs index b6475ba1fe..d50e5fa5e6 100644 --- a/src/Components/Server/test/Circuits/RemoteRendererTest.cs +++ b/src/Components/Server/test/Circuits/RemoteRendererTest.cs @@ -142,7 +142,7 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering var initialClient = new Mock(); initialClient.Setup(c => c.SendCoreAsync(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((string name, object[] value, CancellationToken token) => renderIds.Add((long)value[1])) + .Callback((string name, object[] value, CancellationToken token) => renderIds.Add((long)value[0])) .Returns(firstBatchTCS.Task); var circuitClient = new CircuitClientProxy(initialClient.Object, "connection0"); var renderer = GetRemoteRenderer(serviceProvider, circuitClient); @@ -155,8 +155,8 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering var client = new Mock(); client.Setup(c => c.SendCoreAsync(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((string name, object[] value, CancellationToken token) => renderIds.Add((long)value[1])) - .Returns((n, v, t) => (long)v[1] == 3 ? secondBatchTCS.Task : thirdBatchTCS.Task); + .Callback((string name, object[] value, CancellationToken token) => renderIds.Add((long)value[0])) + .Returns((n, v, t) => (long)v[0] == 3 ? secondBatchTCS.Task : thirdBatchTCS.Task); var componentId = renderer.AssignRootComponentId(component); component.TriggerRender(); @@ -465,7 +465,6 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering return new RemoteRenderer( serviceProvider, NullLoggerFactory.Instance, - new RendererRegistry(), new CircuitOptions(), jsRuntime.Object, circuitClientProxy, diff --git a/src/Components/Server/test/Circuits/TestCircuitHost.cs b/src/Components/Server/test/Circuits/TestCircuitHost.cs index 328120d70c..3e9896e9df 100644 --- a/src/Components/Server/test/Circuits/TestCircuitHost.cs +++ b/src/Components/Server/test/Circuits/TestCircuitHost.cs @@ -18,8 +18,8 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits { internal class TestCircuitHost : CircuitHost { - private TestCircuitHost(string circuitId, IServiceScope scope, CircuitClientProxy client, RendererRegistry rendererRegistry, RemoteRenderer renderer, IReadOnlyList descriptors, RemoteJSRuntime jsRuntime, CircuitHandler[] circuitHandlers, ILogger logger) - : base(circuitId, scope, client, rendererRegistry, renderer, descriptors, jsRuntime, circuitHandlers, logger) + private TestCircuitHost(string circuitId, IServiceScope scope, CircuitClientProxy client, RemoteRenderer renderer, IReadOnlyList descriptors, RemoteJSRuntime jsRuntime, CircuitHandler[] circuitHandlers, ILogger logger) + : base(circuitId, scope, client, renderer, descriptors, jsRuntime, circuitHandlers, logger) { } @@ -37,7 +37,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits { serviceScope = serviceScope ?? Mock.Of(); clientProxy = clientProxy ?? new CircuitClientProxy(Mock.Of(), Guid.NewGuid().ToString()); - var renderRegistry = new RendererRegistry(); var jsRuntime = new RemoteJSRuntime(Options.Create(new CircuitOptions()), Mock.Of>()); if (remoteRenderer == null) @@ -45,7 +44,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits remoteRenderer = new RemoteRenderer( serviceScope.ServiceProvider ?? Mock.Of(), NullLoggerFactory.Instance, - new RendererRegistry(), new CircuitOptions(), jsRuntime, clientProxy, @@ -58,7 +56,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits circuitId ?? Guid.NewGuid().ToString(), serviceScope, clientProxy, - renderRegistry, remoteRenderer, new List(), jsRuntime, diff --git a/src/Components/Web/src/BrowserNavigationManagerInterop.cs b/src/Components/Shared/src/BrowserNavigationManagerInterop.cs similarity index 100% rename from src/Components/Web/src/BrowserNavigationManagerInterop.cs rename to src/Components/Shared/src/BrowserNavigationManagerInterop.cs diff --git a/src/Components/Web/src/RendererRegistryEventDispatcher.cs b/src/Components/Shared/src/WebEventData.cs similarity index 52% rename from src/Components/Web/src/RendererRegistryEventDispatcher.cs rename to src/Components/Shared/src/WebEventData.cs index 7bffa1ec6e..dbcf8c5aa9 100644 --- a/src/Components/Web/src/RendererRegistryEventDispatcher.cs +++ b/src/Components/Shared/src/WebEventData.cs @@ -3,57 +3,47 @@ using System; using System.Text.Json; -using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.JSInterop; namespace Microsoft.AspNetCore.Components.Web { - /// - /// Provides mechanisms for dispatching events to components in a . - /// - public static class RendererRegistryEventDispatcher + internal class WebEventData { - /// - /// For framework use only. - /// - [JSInvokable(nameof(DispatchEvent))] - public static Task DispatchEvent(BrowserEventDescriptor eventDescriptor, string eventArgsJson) + // This class represents the second half of parsing incoming event data, + // once the type of the eventArgs becomes known. + + public static WebEventData Parse(string eventDescriptorJson, string eventArgsJson) { - InterpretEventDescriptor(eventDescriptor); - var eventArgs = ParseEventArgsJson(eventDescriptor.EventArgsType, eventArgsJson); - var renderer = RendererRegistry.Current.Find(eventDescriptor.BrowserRendererId); - return renderer.DispatchEventAsync(eventDescriptor.EventHandlerId, eventDescriptor.EventFieldInfo, eventArgs); + return Parse( + Deserialize(eventDescriptorJson), + eventArgsJson); } - private static void InterpretEventDescriptor(BrowserEventDescriptor eventDescriptor) + public static WebEventData Parse(WebEventDescriptor eventDescriptor, string eventArgsJson) { - // The incoming field value can be either a bool or a string, but since the .NET property - // type is 'object', it will deserialize initially as a JsonElement - var fieldInfo = eventDescriptor.EventFieldInfo; - if (fieldInfo != null) - { - if (fieldInfo.FieldValue is JsonElement attributeValueJsonElement) - { - switch (attributeValueJsonElement.ValueKind) - { - case JsonValueKind.True: - case JsonValueKind.False: - fieldInfo.FieldValue = attributeValueJsonElement.GetBoolean(); - break; - default: - fieldInfo.FieldValue = attributeValueJsonElement.GetString(); - break; - } - } - else - { - // Unanticipated value type. Ensure we don't do anything with it. - eventDescriptor.EventFieldInfo = null; - } - } + return new WebEventData( + eventDescriptor.BrowserRendererId, + eventDescriptor.EventHandlerId, + InterpretEventFieldInfo(eventDescriptor.EventFieldInfo), + ParseEventArgsJson(eventDescriptor.EventArgsType, eventArgsJson)); } + private WebEventData(int browserRendererId, ulong eventHandlerId, EventFieldInfo eventFieldInfo, EventArgs eventArgs) + { + BrowserRendererId = browserRendererId; + EventHandlerId = eventHandlerId; + EventFieldInfo = eventFieldInfo; + EventArgs = eventArgs; + } + + public int BrowserRendererId { get; } + + public ulong EventHandlerId { get; } + + public EventFieldInfo EventFieldInfo { get; } + + public EventArgs EventArgs { get; } + private static EventArgs ParseEventArgsJson(string eventArgsType, string eventArgsJson) { switch (eventArgsType) @@ -83,13 +73,40 @@ namespace Microsoft.AspNetCore.Components.Web case "wheel": return Deserialize(eventArgsJson); default: - throw new ArgumentException($"Unsupported value '{eventArgsType}'.", nameof(eventArgsType)); + throw new ArgumentException($"Unsupported value '{eventArgsType}'.", nameof(eventArgsType)); } } - private static T Deserialize(string eventArgsJson) + private static T Deserialize(string json) { - return JsonSerializer.Deserialize(eventArgsJson, JsonSerializerOptionsProvider.Options); + return JsonSerializer.Deserialize(json, JsonSerializerOptionsProvider.Options); + } + + private static EventFieldInfo InterpretEventFieldInfo(EventFieldInfo fieldInfo) + { + // The incoming field value can be either a bool or a string, but since the .NET property + // type is 'object', it will deserialize initially as a JsonElement + if (fieldInfo?.FieldValue is JsonElement attributeValueJsonElement) + { + switch (attributeValueJsonElement.ValueKind) + { + case JsonValueKind.True: + case JsonValueKind.False: + return new EventFieldInfo + { + ComponentId = fieldInfo.ComponentId, + FieldValue = attributeValueJsonElement.GetBoolean() + }; + default: + return new EventFieldInfo + { + ComponentId = fieldInfo.ComponentId, + FieldValue = attributeValueJsonElement.GetString() + }; + } + } + + return null; } private static ChangeEventArgs DeserializeChangeEventArgs(string eventArgsJson) @@ -113,31 +130,5 @@ namespace Microsoft.AspNetCore.Components.Web } return changeArgs; } - - /// - /// For framework use only. - /// - public class BrowserEventDescriptor - { - /// - /// For framework use only. - /// - public int BrowserRendererId { get; set; } - - /// - /// For framework use only. - /// - public ulong EventHandlerId { get; set; } - - /// - /// For framework use only. - /// - public string EventArgsType { get; set; } - - /// - /// For framework use only. - /// - public EventFieldInfo EventFieldInfo { get; set; } - } } } diff --git a/src/Components/Web.JS/dist/Release/blazor.server.js b/src/Components/Web.JS/dist/Release/blazor.server.js index fc7be4706b..72813d4eb7 100644 --- a/src/Components/Web.JS/dist/Release/blazor.server.js +++ b/src/Components/Web.JS/dist/Release/blazor.server.js @@ -1,15 +1,15 @@ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=49)}([function(e,t,n){"use strict";var r;n.d(t,"a",function(){return r}),function(e){e[e.Trace=0]="Trace",e[e.Debug=1]="Debug",e[e.Information=2]="Information",e[e.Warning=3]="Warning",e[e.Error=4]="Error",e[e.Critical=5]="Critical",e[e.None=6]="None"}(r||(r={}))},function(e,t,n){"use strict";n.d(t,"a",function(){return a}),n.d(t,"c",function(){return c}),n.d(t,"f",function(){return u}),n.d(t,"g",function(){return l}),n.d(t,"h",function(){return f}),n.d(t,"e",function(){return h}),n.d(t,"d",function(){return p}),n.d(t,"b",function(){return d});var r=n(0),o=n(6),i=function(e,t,n,r){return new(n||(n=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(e){i(e)}}function a(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(s,a)}c((r=r.apply(e,t||[])).next())})},s=function(e,t){var n,r,o,i,s={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(i){return function(a){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;s;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return s.label++,{value:i[1],done:!1};case 5:s.label++,r=i[1],i=[0];continue;case 7:i=s.ops.pop(),s.trys.pop();continue;default:if(!(o=(o=s.trys).length>0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]-1&&this.subject.observers.splice(e,1),0===this.subject.observers.length&&this.subject.cancelCallback&&this.subject.cancelCallback().catch(function(e){})},e}(),d=function(){function e(e){this.minimumLogLevel=e,this.outputConsole=console}return e.prototype.log=function(e,t){if(e>=this.minimumLogLevel)switch(e){case r.a.Critical:case r.a.Error:this.outputConsole.error("["+(new Date).toISOString()+"] "+r.a[e]+": "+t);break;case r.a.Warning:this.outputConsole.warn("["+(new Date).toISOString()+"] "+r.a[e]+": "+t);break;case r.a.Information:this.outputConsole.info("["+(new Date).toISOString()+"] "+r.a[e]+": "+t);break;default:this.outputConsole.log("["+(new Date).toISOString()+"] "+r.a[e]+": "+t)}},e}()},function(e,t,n){"use strict";n.r(t);var r,o,i=n(3),s=n(4),a=n(43),c=n(0),u=(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),l=function(e){function t(t){var n=e.call(this)||this;return n.logger=t,n}return u(t,e),t.prototype.send=function(e){var t=this;return e.abortSignal&&e.abortSignal.aborted?Promise.reject(new i.a):e.method?e.url?new Promise(function(n,r){var o=new XMLHttpRequest;o.open(e.method,e.url,!0),o.withCredentials=!0,o.setRequestHeader("X-Requested-With","XMLHttpRequest"),o.setRequestHeader("Content-Type","text/plain;charset=UTF-8");var a=e.headers;a&&Object.keys(a).forEach(function(e){o.setRequestHeader(e,a[e])}),e.responseType&&(o.responseType=e.responseType),e.abortSignal&&(e.abortSignal.onabort=function(){o.abort(),r(new i.a)}),e.timeout&&(o.timeout=e.timeout),o.onload=function(){e.abortSignal&&(e.abortSignal.onabort=null),o.status>=200&&o.status<300?n(new s.b(o.status,o.statusText,o.response||o.responseText)):r(new i.b(o.statusText,o.status))},o.onerror=function(){t.logger.log(c.a.Warning,"Error from HTTP request. "+o.status+": "+o.statusText+"."),r(new i.b(o.statusText,o.status))},o.ontimeout=function(){t.logger.log(c.a.Warning,"Timeout from HTTP request."),r(new i.c)},o.send(e.content||"")}):Promise.reject(new Error("No url defined.")):Promise.reject(new Error("No method defined."))},t}(s.a),f=function(){var e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),h=function(e){function t(t){var n=e.call(this)||this;return"undefined"!=typeof XMLHttpRequest?n.httpClient=new l(t):n.httpClient=new a.a(t),n}return f(t,e),t.prototype.send=function(e){return e.abortSignal&&e.abortSignal.aborted?Promise.reject(new i.a):e.method?e.url?this.httpClient.send(e):Promise.reject(new Error("No url defined.")):Promise.reject(new Error("No method defined."))},t.prototype.getCookieString=function(e){return this.httpClient.getCookieString(e)},t}(s.a),p=n(44);!function(e){e[e.Invocation=1]="Invocation",e[e.StreamItem=2]="StreamItem",e[e.Completion=3]="Completion",e[e.StreamInvocation=4]="StreamInvocation",e[e.CancelInvocation=5]="CancelInvocation",e[e.Ping=6]="Ping",e[e.Close=7]="Close"}(o||(o={}));var d,g=n(1),y=function(){function e(){this.observers=[]}return e.prototype.next=function(e){for(var t=0,n=this.observers;t0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0?[2,Promise.reject(new Error("Unable to connect to the server with any of the available transports. "+i.join(" ")))]:[2,Promise.reject(new Error("None of the transports supported by the client are supported by the server."))]}})})},e.prototype.constructTransport=function(e){switch(e){case E.WebSockets:if(!this.options.WebSocket)throw new Error("'WebSocket' is not supported in your environment.");return new A(this.httpClient,this.accessTokenFactory,this.logger,this.options.logMessageContent||!1,this.options.WebSocket);case E.ServerSentEvents:if(!this.options.EventSource)throw new Error("'EventSource' is not supported in your environment.");return new O(this.httpClient,this.accessTokenFactory,this.logger,this.options.logMessageContent||!1,this.options.EventSource);case E.LongPolling:return new x(this.httpClient,this.accessTokenFactory,this.logger,this.options.logMessageContent||!1);default:throw new Error("Unknown transport: "+e+".")}},e.prototype.startTransport=function(e,t){var n=this;return this.transport.onreceive=this.onreceive,this.transport.onclose=function(e){return n.stopConnection(e)},this.transport.connect(e,t)},e.prototype.resolveTransportOrError=function(e,t,n){var r=E[e.transport];if(null==r)return this.logger.log(c.a.Debug,"Skipping transport '"+e.transport+"' because it is not supported by this client."),new Error("Skipping transport '"+e.transport+"' because it is not supported by this client.");if(!function(e,t){return!e||0!=(t&e)}(t,r))return this.logger.log(c.a.Debug,"Skipping transport '"+E[r]+"' because it was disabled by the client."),new Error("'"+E[r]+"' is disabled by the client.");if(!(e.transferFormats.map(function(e){return S[e]}).indexOf(n)>=0))return this.logger.log(c.a.Debug,"Skipping transport '"+E[r]+"' because it does not support the requested transfer format '"+S[n]+"'."),new Error("'"+E[r]+"' does not support "+S[n]+".");if(r===E.WebSockets&&!this.options.WebSocket||r===E.ServerSentEvents&&!this.options.EventSource)return this.logger.log(c.a.Debug,"Skipping transport '"+E[r]+"' because it is not supported in your environment.'"),new Error("'"+E[r]+"' is not supported in your environment.");this.logger.log(c.a.Debug,"Selecting transport '"+E[r]+"'.");try{return this.constructTransport(r)}catch(e){return e}},e.prototype.isITransport=function(e){return e&&"object"==typeof e&&"connect"in e},e.prototype.stopConnection=function(e){if(this.logger.log(c.a.Debug,"HttpConnection.stopConnection("+e+") called while in state "+this.connectionState+"."),this.transport=void 0,e=this.stopError||e,this.stopError=void 0,"Disconnected"!==this.connectionState)if("Connecting "!==this.connectionState){if("Disconnecting"===this.connectionState&&this.stopPromiseResolver(),e?this.logger.log(c.a.Error,"Connection disconnected with error '"+e+"'."):this.logger.log(c.a.Information,"Connection disconnected."),this.connectionId=void 0,this.connectionState="Disconnected",this.onclose&&this.connectionStarted){this.connectionStarted=!1;try{this.onclose(e)}catch(t){this.logger.log(c.a.Error,"HttpConnection.onclose("+e+") threw error '"+t+"'.")}}}else this.logger.log(c.a.Warning,"Call to HttpConnection.stopConnection("+e+") was ignored because the connection hasn't yet left the in the connecting state.");else this.logger.log(c.a.Debug,"Call to HttpConnection.stopConnection("+e+") was ignored because the connection is already in the disconnected state.")},e.prototype.resolveUrl=function(e){if(0===e.lastIndexOf("https://",0)||0===e.lastIndexOf("http://",0))return e;if(!g.c.isBrowser||!window.document)throw new Error("Cannot resolve '"+e+"'.");var t=window.document.createElement("a");return t.href=e,this.logger.log(c.a.Information,"Normalizing '"+e+"' to '"+t.href+"'."),t.href},e.prototype.resolveNegotiateUrl=function(e){var t=e.indexOf("?"),n=e.substring(0,-1===t?e.length:t);return"/"!==n[n.length-1]&&(n+="/"),n+="negotiate",n+=-1===t?"":e.substring(t)},e}();var q=function(){function e(e){this.transport=e,this.buffer=[],this.executing=!0,this.sendBufferedData=new W,this.transportResult=new W,this.sendLoopPromise=this.sendLoop()}return e.prototype.send=function(e){return this.bufferData(e),this.transportResult||(this.transportResult=new W),this.transportResult.promise},e.prototype.stop=function(){return this.executing=!1,this.sendBufferedData.resolve(),this.sendLoopPromise},e.prototype.bufferData=function(e){if(this.buffer.length&&typeof this.buffer[0]!=typeof e)throw new Error("Expected data to be of type "+typeof this.buffer+" but was of type "+typeof e);this.buffer.push(e),this.sendBufferedData.resolve()},e.prototype.sendLoop=function(){return B(this,void 0,void 0,function(){var t,n,r;return j(this,function(o){switch(o.label){case 0:return[4,this.sendBufferedData.promise];case 1:if(o.sent(),!this.executing)return this.transportResult&&this.transportResult.reject("Connection stopped."),[3,6];this.sendBufferedData=new W,t=this.transportResult,this.transportResult=void 0,n="string"==typeof this.buffer[0]?this.buffer.join(""):e.concatBuffers(this.buffer),this.buffer.length=0,o.label=2;case 2:return o.trys.push([2,4,,5]),[4,this.transport.send(n)];case 3:return o.sent(),t.resolve(),[3,5];case 4:return r=o.sent(),t.reject(r),[3,5];case 5:return[3,0];case 6:return[2]}})})},e.concatBuffers=function(e){for(var t=e.map(function(e){return e.byteLength}).reduce(function(e,t){return e+t}),n=new Uint8Array(t),r=0,o=0,i=e;o0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]-1&&this.subject.observers.splice(e,1),0===this.subject.observers.length&&this.subject.cancelCallback&&this.subject.cancelCallback().catch(function(e){})},e}(),d=function(){function e(e){this.minimumLogLevel=e,this.outputConsole=console}return e.prototype.log=function(e,t){if(e>=this.minimumLogLevel)switch(e){case r.a.Critical:case r.a.Error:this.outputConsole.error("["+(new Date).toISOString()+"] "+r.a[e]+": "+t);break;case r.a.Warning:this.outputConsole.warn("["+(new Date).toISOString()+"] "+r.a[e]+": "+t);break;case r.a.Information:this.outputConsole.info("["+(new Date).toISOString()+"] "+r.a[e]+": "+t);break;default:this.outputConsole.log("["+(new Date).toISOString()+"] "+r.a[e]+": "+t)}},e}()},function(e,t,n){"use strict";n.r(t);var r,o,i=n(3),a=n(4),s=n(43),c=n(0),u=(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),l=function(e){function t(t){var n=e.call(this)||this;return n.logger=t,n}return u(t,e),t.prototype.send=function(e){var t=this;return e.abortSignal&&e.abortSignal.aborted?Promise.reject(new i.a):e.method?e.url?new Promise(function(n,r){var o=new XMLHttpRequest;o.open(e.method,e.url,!0),o.withCredentials=!0,o.setRequestHeader("X-Requested-With","XMLHttpRequest"),o.setRequestHeader("Content-Type","text/plain;charset=UTF-8");var s=e.headers;s&&Object.keys(s).forEach(function(e){o.setRequestHeader(e,s[e])}),e.responseType&&(o.responseType=e.responseType),e.abortSignal&&(e.abortSignal.onabort=function(){o.abort(),r(new i.a)}),e.timeout&&(o.timeout=e.timeout),o.onload=function(){e.abortSignal&&(e.abortSignal.onabort=null),o.status>=200&&o.status<300?n(new a.b(o.status,o.statusText,o.response||o.responseText)):r(new i.b(o.statusText,o.status))},o.onerror=function(){t.logger.log(c.a.Warning,"Error from HTTP request. "+o.status+": "+o.statusText+"."),r(new i.b(o.statusText,o.status))},o.ontimeout=function(){t.logger.log(c.a.Warning,"Timeout from HTTP request."),r(new i.c)},o.send(e.content||"")}):Promise.reject(new Error("No url defined.")):Promise.reject(new Error("No method defined."))},t}(a.a),f=function(){var e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),h=function(e){function t(t){var n=e.call(this)||this;return"undefined"!=typeof XMLHttpRequest?n.httpClient=new l(t):n.httpClient=new s.a(t),n}return f(t,e),t.prototype.send=function(e){return e.abortSignal&&e.abortSignal.aborted?Promise.reject(new i.a):e.method?e.url?this.httpClient.send(e):Promise.reject(new Error("No url defined.")):Promise.reject(new Error("No method defined."))},t.prototype.getCookieString=function(e){return this.httpClient.getCookieString(e)},t}(a.a),p=n(44);!function(e){e[e.Invocation=1]="Invocation",e[e.StreamItem=2]="StreamItem",e[e.Completion=3]="Completion",e[e.StreamInvocation=4]="StreamInvocation",e[e.CancelInvocation=5]="CancelInvocation",e[e.Ping=6]="Ping",e[e.Close=7]="Close"}(o||(o={}));var d,g=n(1),y=function(){function e(){this.observers=[]}return e.prototype.next=function(e){for(var t=0,n=this.observers;t0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0?[2,Promise.reject(new Error("Unable to connect to the server with any of the available transports. "+i.join(" ")))]:[2,Promise.reject(new Error("None of the transports supported by the client are supported by the server."))]}})})},e.prototype.constructTransport=function(e){switch(e){case E.WebSockets:if(!this.options.WebSocket)throw new Error("'WebSocket' is not supported in your environment.");return new A(this.httpClient,this.accessTokenFactory,this.logger,this.options.logMessageContent||!1,this.options.WebSocket);case E.ServerSentEvents:if(!this.options.EventSource)throw new Error("'EventSource' is not supported in your environment.");return new O(this.httpClient,this.accessTokenFactory,this.logger,this.options.logMessageContent||!1,this.options.EventSource);case E.LongPolling:return new x(this.httpClient,this.accessTokenFactory,this.logger,this.options.logMessageContent||!1);default:throw new Error("Unknown transport: "+e+".")}},e.prototype.startTransport=function(e,t){var n=this;return this.transport.onreceive=this.onreceive,this.transport.onclose=function(e){return n.stopConnection(e)},this.transport.connect(e,t)},e.prototype.resolveTransportOrError=function(e,t,n){var r=E[e.transport];if(null==r)return this.logger.log(c.a.Debug,"Skipping transport '"+e.transport+"' because it is not supported by this client."),new Error("Skipping transport '"+e.transport+"' because it is not supported by this client.");if(!function(e,t){return!e||0!=(t&e)}(t,r))return this.logger.log(c.a.Debug,"Skipping transport '"+E[r]+"' because it was disabled by the client."),new Error("'"+E[r]+"' is disabled by the client.");if(!(e.transferFormats.map(function(e){return S[e]}).indexOf(n)>=0))return this.logger.log(c.a.Debug,"Skipping transport '"+E[r]+"' because it does not support the requested transfer format '"+S[n]+"'."),new Error("'"+E[r]+"' does not support "+S[n]+".");if(r===E.WebSockets&&!this.options.WebSocket||r===E.ServerSentEvents&&!this.options.EventSource)return this.logger.log(c.a.Debug,"Skipping transport '"+E[r]+"' because it is not supported in your environment.'"),new Error("'"+E[r]+"' is not supported in your environment.");this.logger.log(c.a.Debug,"Selecting transport '"+E[r]+"'.");try{return this.constructTransport(r)}catch(e){return e}},e.prototype.isITransport=function(e){return e&&"object"==typeof e&&"connect"in e},e.prototype.stopConnection=function(e){if(this.logger.log(c.a.Debug,"HttpConnection.stopConnection("+e+") called while in state "+this.connectionState+"."),this.transport=void 0,e=this.stopError||e,this.stopError=void 0,"Disconnected"!==this.connectionState)if("Connecting "!==this.connectionState){if("Disconnecting"===this.connectionState&&this.stopPromiseResolver(),e?this.logger.log(c.a.Error,"Connection disconnected with error '"+e+"'."):this.logger.log(c.a.Information,"Connection disconnected."),this.connectionId=void 0,this.connectionState="Disconnected",this.onclose&&this.connectionStarted){this.connectionStarted=!1;try{this.onclose(e)}catch(t){this.logger.log(c.a.Error,"HttpConnection.onclose("+e+") threw error '"+t+"'.")}}}else this.logger.log(c.a.Warning,"Call to HttpConnection.stopConnection("+e+") was ignored because the connection hasn't yet left the in the connecting state.");else this.logger.log(c.a.Debug,"Call to HttpConnection.stopConnection("+e+") was ignored because the connection is already in the disconnected state.")},e.prototype.resolveUrl=function(e){if(0===e.lastIndexOf("https://",0)||0===e.lastIndexOf("http://",0))return e;if(!g.c.isBrowser||!window.document)throw new Error("Cannot resolve '"+e+"'.");var t=window.document.createElement("a");return t.href=e,this.logger.log(c.a.Information,"Normalizing '"+e+"' to '"+t.href+"'."),t.href},e.prototype.resolveNegotiateUrl=function(e){var t=e.indexOf("?"),n=e.substring(0,-1===t?e.length:t);return"/"!==n[n.length-1]&&(n+="/"),n+="negotiate",n+=-1===t?"":e.substring(t)},e}();var q=function(){function e(e){this.transport=e,this.buffer=[],this.executing=!0,this.sendBufferedData=new W,this.transportResult=new W,this.sendLoopPromise=this.sendLoop()}return e.prototype.send=function(e){return this.bufferData(e),this.transportResult||(this.transportResult=new W),this.transportResult.promise},e.prototype.stop=function(){return this.executing=!1,this.sendBufferedData.resolve(),this.sendLoopPromise},e.prototype.bufferData=function(e){if(this.buffer.length&&typeof this.buffer[0]!=typeof e)throw new Error("Expected data to be of type "+typeof this.buffer+" but was of type "+typeof e);this.buffer.push(e),this.sendBufferedData.resolve()},e.prototype.sendLoop=function(){return B(this,void 0,void 0,function(){var t,n,r;return j(this,function(o){switch(o.label){case 0:return[4,this.sendBufferedData.promise];case 1:if(o.sent(),!this.executing)return this.transportResult&&this.transportResult.reject("Connection stopped."),[3,6];this.sendBufferedData=new W,t=this.transportResult,this.transportResult=void 0,n="string"==typeof this.buffer[0]?this.buffer.join(""):e.concatBuffers(this.buffer),this.buffer.length=0,o.label=2;case 2:return o.trys.push([2,4,,5]),[4,this.transport.send(n)];case 3:return o.sent(),t.resolve(),[3,5];case 4:return r=o.sent(),t.reject(r),[3,5];case 5:return[3,0];case 6:return[2]}})})},e.concatBuffers=function(e){for(var t=e.map(function(e){return e.byteLength}).reduce(function(e,t){return e+t}),n=new Uint8Array(t),r=0,o=0,i=e;o * @license MIT */ -var r=n(50),o=n(51),i=n(52);function s(){return c.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function a(e,t){if(s()=s())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+s().toString(16)+" bytes");return 0|e}function d(e,t){if(c.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return F(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return H(e).length;default:if(r)return F(e).length;t=(""+t).toLowerCase(),r=!0}}function g(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function y(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=c.from(t,r)),c.isBuffer(t))return 0===t.length?-1:v(e,t,n,r,o);if("number"==typeof t)return t&=255,c.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):v(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function v(e,t,n,r,o){var i,s=1,a=e.length,c=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;s=2,a/=2,c/=2,n/=2}function u(e,t){return 1===s?e[t]:e.readUInt16BE(t*s)}if(o){var l=-1;for(i=n;ia&&(n=a-c),i=n;i>=0;i--){for(var f=!0,h=0;ho&&(r=o):r=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");r>i/2&&(r=i/2);for(var s=0;s>8,o=n%256,i.push(o),i.push(r);return i}(t,e.length-n),e,n,r)}function _(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function I(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:u>223?3:u>191?2:1;if(o+f<=n)switch(f){case 1:u<128&&(l=u);break;case 2:128==(192&(i=e[o+1]))&&(c=(31&u)<<6|63&i)>127&&(l=c);break;case 3:i=e[o+1],s=e[o+2],128==(192&i)&&128==(192&s)&&(c=(15&u)<<12|(63&i)<<6|63&s)>2047&&(c<55296||c>57343)&&(l=c);break;case 4:i=e[o+1],s=e[o+2],a=e[o+3],128==(192&i)&&128==(192&s)&&128==(192&a)&&(c=(15&u)<<18|(63&i)<<12|(63&s)<<6|63&a)>65535&&c<1114112&&(l=c)}null===l?(l=65533,f=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),o+=f}return function(e){var t=e.length;if(t<=T)return String.fromCharCode.apply(String,e);var n="",r=0;for(;rthis.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return x(this,t,n);case"utf8":case"utf-8":return I(this,t,n);case"ascii":return k(this,t,n);case"latin1":case"binary":return P(this,t,n);case"base64":return _(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return R(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}.apply(this,arguments)},c.prototype.equals=function(e){if(!c.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===c.compare(this,e)},c.prototype.inspect=function(){var e="",n=t.INSPECT_MAX_BYTES;return this.length>0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},c.prototype.compare=function(e,t,n,r,o){if(!c.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(this===e)return 0;for(var i=(o>>>=0)-(r>>>=0),s=(n>>>=0)-(t>>>=0),a=Math.min(i,s),u=this.slice(r,o),l=e.slice(t,n),f=0;fo)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var i=!1;;)switch(r){case"hex":return b(this,e,t,n);case"utf8":case"utf-8":return m(this,e,t,n);case"ascii":return w(this,e,t,n);case"latin1":case"binary":return E(this,e,t,n);case"base64":return S(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return C(this,e,t,n);default:if(i)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),i=!0}},c.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var T=4096;function k(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",i=t;in)throw new RangeError("Trying to access beyond buffer length")}function O(e,t,n,r,o,i){if(!c.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function L(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function M(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function A(e,t,n,r,o,i){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function B(e,t,n,r,i){return i||A(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function j(e,t,n,r,i){return i||A(e,0,n,8),o.write(e,t,n,r,52,8),n+8}c.prototype.slice=function(e,t){var n,r=this.length;if((e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},c.prototype.readUInt8=function(e,t){return t||D(e,1,this.length),this[e]},c.prototype.readUInt16LE=function(e,t){return t||D(e,2,this.length),this[e]|this[e+1]<<8},c.prototype.readUInt16BE=function(e,t){return t||D(e,2,this.length),this[e]<<8|this[e+1]},c.prototype.readUInt32LE=function(e,t){return t||D(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},c.prototype.readUInt32BE=function(e,t){return t||D(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},c.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||D(e,t,this.length);for(var r=this[e],o=1,i=0;++i=(o*=128)&&(r-=Math.pow(2,8*t)),r},c.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||D(e,t,this.length);for(var r=t,o=1,i=this[e+--r];r>0&&(o*=256);)i+=this[e+--r]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},c.prototype.readInt8=function(e,t){return t||D(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},c.prototype.readInt16LE=function(e,t){t||D(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt16BE=function(e,t){t||D(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt32LE=function(e,t){return t||D(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},c.prototype.readInt32BE=function(e,t){return t||D(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},c.prototype.readFloatLE=function(e,t){return t||D(e,4,this.length),o.read(this,e,!0,23,4)},c.prototype.readFloatBE=function(e,t){return t||D(e,4,this.length),o.read(this,e,!1,23,4)},c.prototype.readDoubleLE=function(e,t){return t||D(e,8,this.length),o.read(this,e,!0,52,8)},c.prototype.readDoubleBE=function(e,t){return t||D(e,8,this.length),o.read(this,e,!1,52,8)},c.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||O(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+n},c.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,1,255,0),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},c.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):L(this,e,t,!0),t+2},c.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):L(this,e,t,!1),t+2},c.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):M(this,e,t,!0),t+4},c.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):M(this,e,t,!1),t+4},c.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);O(this,e,t,n,o-1,-o)}var i=0,s=1,a=0;for(this[t]=255&e;++i>0)-a&255;return t+n},c.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);O(this,e,t,n,o-1,-o)}var i=n-1,s=1,a=0;for(this[t+i]=255&e;--i>=0&&(s*=256);)e<0&&0===a&&0!==this[t+i+1]&&(a=1),this[t+i]=(e/s>>0)-a&255;return t+n},c.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,1,127,-128),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},c.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):L(this,e,t,!0),t+2},c.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):L(this,e,t,!1),t+2},c.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,2147483647,-2147483648),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):M(this,e,t,!0),t+4},c.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):M(this,e,t,!1),t+4},c.prototype.writeFloatLE=function(e,t,n){return B(this,e,t,!0,n)},c.prototype.writeFloatBE=function(e,t,n){return B(this,e,t,!1,n)},c.prototype.writeDoubleLE=function(e,t,n){return j(this,e,t,!0,n)},c.prototype.writeDoubleBE=function(e,t,n){return j(this,e,t,!1,n)},c.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(i<1e3||!c.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(s+1===r){(t-=3)>-1&&i.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&i.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;i.push(n)}else if(n<2048){if((t-=2)<0)break;i.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;i.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return i}function H(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(U,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function q(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(this,n(10))},function(e,t,n){"use strict";n.d(t,"a",function(){return r});var r=function(){function e(){}return e.prototype.log=function(e,t){},e.instance=new e,e}()},function(e,t,n){"use strict";n.d(t,"a",function(){return r});var r=function(){function e(){}return e.write=function(t){return""+t+e.RecordSeparator},e.parse=function(t){if(t[t.length-1]!==e.RecordSeparator)throw new Error("Message is incomplete.");var n=t.split(e.RecordSeparator);return n.pop(),n},e.RecordSeparatorCode=30,e.RecordSeparator=String.fromCharCode(e.RecordSeparatorCode),e}()},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(25),n(9);var r=n(26),o=n(16),i={},s=!1;function a(e,t,n){var o=i[e];o||(o=i[e]=new r.BrowserRenderer(e)),o.attachRootComponentToLogicalElement(n,t)}t.attachRootComponentToLogicalElement=a,t.attachRootComponentToElement=function(e,t,n){var r=document.querySelector(t);if(!r)throw new Error("Could not find any element matching selector '"+t+"'.");a(e,o.toLogicalElement(r,!0),n)},t.renderBatch=function(e,t){var n=i[e];if(!n)throw new Error("There is no browser renderer with ID "+e+".");for(var r=t.arrayRangeReader,o=t.updatedComponents(),a=r.values(o),c=r.count(o),u=t.referenceFrames(),l=r.values(u),f=t.diffReader,h=0;h=0,"must have a non-negative type"),o(s,"must have a decode function"),this.registerEncoder(function(e){return e instanceof t},function(t){var o=i(),s=r.allocUnsafe(1);return s.writeInt8(e,0),o.append(s),o.append(n(t)),o}),this.registerDecoder(e,s),this},registerEncoder:function(e,n){return o(e,"must have an encode function"),o(n,"must have an encode function"),t.push({check:e,encode:n}),this},registerDecoder:function(e,t){return o(e>=0,"must have a non-negative type"),o(t,"must have a decode function"),n.push({type:e,decode:t}),this},encoder:s.encoder,decoder:s.decoder,buffer:!0,type:"msgpack5",IncompleteBufferError:a.IncompleteBufferError}}},function(e,t,n){var r=n(5),o=r.Buffer;function i(e,t){for(var n in e)t[n]=e[n]}function s(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=s),i(o,s),s.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},s.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},s.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},s.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){"use strict";var r;!function(e){window.DotNet=e;var t=[],n={},r={},o=1,i=null;function s(e){t.push(e)}function a(e,t){for(var n=[],r=2;r0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return e[r]=[],e}function a(e,t,n){var i=e;if(e instanceof Comment&&(u(i)&&u(i).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(c(i))throw new Error("Not implemented: moving existing logical children");var s=u(t);if(n0;)e(r,0);var i=r;i.parentNode.removeChild(i)},t.getLogicalParent=c,t.getLogicalSiblingEnd=function(e){return e[i]||null},t.getLogicalChild=function(e,t){return u(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===l(e).namespaceURI},t.getLogicalChildrenArray=u,t.permuteLogicalChildren=function(e,t){var n=u(e);t.forEach(function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=c(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)}),t.forEach(function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):h(r,e)}),t.forEach(function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,i=r;i;){var s=i.nextSibling;if(n.insertBefore(i,t),i===o)break;i=s}n.removeChild(t)}),t.forEach(function(e){n[e.toSiblingIndex]=e.moveRangeStart})},t.getClosestDomElement=l},function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),t.dispatchEvent=function(e,t){if(!r)throw new Error("eventDispatcher not initialized. Call 'setEventDispatcher' to configure it.");return r(e,t)},t.setEventDispatcher=function(e){r=e}},function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function s(){throw new Error("clearTimeout has not been defined")}function a(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:s}catch(e){r=s}}();var c,u=[],l=!1,f=-1;function h(){l&&c&&(l=!1,c.length?u=c.concat(u):f=-1,u.length&&p())}function p(){if(!l){var e=a(h);l=!0;for(var t=u.length;t;){for(c=u,u=[];++f1)for(var n=1;n0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]this.length)&&(r=this.length),n>=this.length)return e||i.alloc(0);if(r<=0)return e||i.alloc(0);var o,s,a=!!e,c=this._offset(n),u=r-n,l=u,f=a&&t||0,h=c[1];if(0===n&&r==this.length){if(!a)return 1===this._bufs.length?this._bufs[0]:i.concat(this._bufs,this.length);for(s=0;s(o=this._bufs[s].length-h))){this._bufs[s].copy(e,f,h,h+l);break}this._bufs[s].copy(e,f,h),f+=o,l-=o,h&&(h=0)}return e},s.prototype.shallowSlice=function(e,t){e=e||0,t=t||this.length,e<0&&(e+=this.length),t<0&&(t+=this.length);var n=this._offset(e),r=this._offset(t),o=this._bufs.slice(n[0],r[0]+1);return 0==r[1]?o.pop():o[o.length-1]=o[o.length-1].slice(0,r[1]),0!=n[1]&&(o[0]=o[0].slice(n[1])),new s(o)},s.prototype.toString=function(e,t,n){return this.slice(t,n).toString(e)},s.prototype.consume=function(e){for(;this._bufs.length;){if(!(e>=this._bufs[0].length)){this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift()}return this},s.prototype.duplicate=function(){for(var e=0,t=new s;e0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]=i)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(e){return"[Circular]"}default:return e}}),c=r[n];n=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),d(n)?r.showHidden=n:n&&t._extend(r,n),b(r.showHidden)&&(r.showHidden=!1),b(r.depth)&&(r.depth=2),b(r.colors)&&(r.colors=!1),b(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=c),l(r,e,r.depth)}function c(e,t){var n=a.styles[t];return n?"["+a.colors[n][0]+"m"+e+"["+a.colors[n][1]+"m":e}function u(e,t){return e}function l(e,n,r){if(e.customInspect&&n&&C(n.inspect)&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var o=n.inspect(r,e);return v(o)||(o=l(e,o,r)),o}var i=function(e,t){if(b(t))return e.stylize("undefined","undefined");if(v(t)){var n="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(n,"string")}if(y(t))return e.stylize(""+t,"number");if(d(t))return e.stylize(""+t,"boolean");if(g(t))return e.stylize("null","null")}(e,n);if(i)return i;var s=Object.keys(n),a=function(e){var t={};return e.forEach(function(e,n){t[e]=!0}),t}(s);if(e.showHidden&&(s=Object.getOwnPropertyNames(n)),S(n)&&(s.indexOf("message")>=0||s.indexOf("description")>=0))return f(n);if(0===s.length){if(C(n)){var c=n.name?": "+n.name:"";return e.stylize("[Function"+c+"]","special")}if(m(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(E(n))return e.stylize(Date.prototype.toString.call(n),"date");if(S(n))return f(n)}var u,w="",_=!1,I=["{","}"];(p(n)&&(_=!0,I=["[","]"]),C(n))&&(w=" [Function"+(n.name?": "+n.name:"")+"]");return m(n)&&(w=" "+RegExp.prototype.toString.call(n)),E(n)&&(w=" "+Date.prototype.toUTCString.call(n)),S(n)&&(w=" "+f(n)),0!==s.length||_&&0!=n.length?r<0?m(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special"):(e.seen.push(n),u=_?function(e,t,n,r,o){for(var i=[],s=0,a=t.length;s=0&&0,e+t.replace(/\u001b\[\d\d?m/g,"").length+1},0)>60)return n[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+n[1];return n[0]+t+" "+e.join(", ")+" "+n[1]}(u,w,I)):I[0]+w+I[1]}function f(e){return"["+Error.prototype.toString.call(e)+"]"}function h(e,t,n,r,o,i){var s,a,c;if((c=Object.getOwnPropertyDescriptor(t,o)||{value:t[o]}).get?a=c.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):c.set&&(a=e.stylize("[Setter]","special")),k(r,o)||(s="["+o+"]"),a||(e.seen.indexOf(c.value)<0?(a=g(n)?l(e,c.value,null):l(e,c.value,n-1)).indexOf("\n")>-1&&(a=i?a.split("\n").map(function(e){return" "+e}).join("\n").substr(2):"\n"+a.split("\n").map(function(e){return" "+e}).join("\n")):a=e.stylize("[Circular]","special")),b(s)){if(i&&o.match(/^\d+$/))return a;(s=JSON.stringify(""+o)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(s=s.substr(1,s.length-2),s=e.stylize(s,"name")):(s=s.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),s=e.stylize(s,"string"))}return s+": "+a}function p(e){return Array.isArray(e)}function d(e){return"boolean"==typeof e}function g(e){return null===e}function y(e){return"number"==typeof e}function v(e){return"string"==typeof e}function b(e){return void 0===e}function m(e){return w(e)&&"[object RegExp]"===_(e)}function w(e){return"object"==typeof e&&null!==e}function E(e){return w(e)&&"[object Date]"===_(e)}function S(e){return w(e)&&("[object Error]"===_(e)||e instanceof Error)}function C(e){return"function"==typeof e}function _(e){return Object.prototype.toString.call(e)}function I(e){return e<10?"0"+e.toString(10):e.toString(10)}t.debuglog=function(n){if(b(i)&&(i=e.env.NODE_DEBUG||""),n=n.toUpperCase(),!s[n])if(new RegExp("\\b"+n+"\\b","i").test(i)){var r=e.pid;s[n]=function(){var e=t.format.apply(t,arguments);console.error("%s %d: %s",n,r,e)}}else s[n]=function(){};return s[n]},t.inspect=a,a.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},a.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},t.isArray=p,t.isBoolean=d,t.isNull=g,t.isNullOrUndefined=function(e){return null==e},t.isNumber=y,t.isString=v,t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=b,t.isRegExp=m,t.isObject=w,t.isDate=E,t.isError=S,t.isFunction=C,t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=n(54);var T=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function k(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.log=function(){var e,n;console.log("%s - %s",(e=new Date,n=[I(e.getHours()),I(e.getMinutes()),I(e.getSeconds())].join(":"),[e.getDate(),T[e.getMonth()],n].join(" ")),t.format.apply(t,arguments))},t.inherits=n(55),t._extend=function(e,t){if(!t||!w(t))return e;for(var n=Object.keys(t),r=n.length;r--;)e[n[r]]=t[n[r]];return e};var P="undefined"!=typeof Symbol?Symbol("util.promisify.custom"):void 0;function x(e,t){if(!e){var n=new Error("Promise was rejected with a falsy value");n.reason=e,e=n}return t(e)}t.promisify=function(e){if("function"!=typeof e)throw new TypeError('The "original" argument must be of type Function');if(P&&e[P]){var t;if("function"!=typeof(t=e[P]))throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,P,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var t,n,r=new Promise(function(e,r){t=e,n=r}),o=[],i=0;i0?("string"==typeof t||s.objectMode||Object.getPrototypeOf(t)===u.prototype||(t=function(e){return u.from(e)}(t)),r?s.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):E(e,s,t,!0):s.ended?e.emit("error",new Error("stream.push() after EOF")):(s.reading=!1,s.decoder&&!n?(t=s.decoder.write(t),s.objectMode||0!==t.length?E(e,s,t,!1):T(e,s)):E(e,s,t,!1))):r||(s.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=S?e=S:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function _(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(p("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?o.nextTick(I,e):I(e))}function I(e){p("emit readable"),e.emit("readable"),R(e)}function T(e,t){t.readingMore||(t.readingMore=!0,o.nextTick(k,e,t))}function k(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=function(e,t,n){var r;ei.length?i.length:e;if(s===i.length?o+=i:o+=i.slice(0,e),0===(e-=s)){s===i.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=i.slice(s));break}++r}return t.length-=r,o}(e,t):function(e,t){var n=u.allocUnsafe(e),r=t.head,o=1;r.data.copy(n),e-=r.data.length;for(;r=r.next;){var i=r.data,s=e>i.length?i.length:e;if(i.copy(n,n.length-e,0,s),0===(e-=s)){s===i.length?(++o,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=i.slice(s));break}++o}return t.length-=o,n}(e,t);return r}(e,t.buffer,t.decoder),n);var n}function O(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,o.nextTick(L,t,e))}function L(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function M(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return p("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?O(this):_(this),null;if(0===(e=C(e,t))&&t.ended)return 0===t.length&&O(this),null;var r,o=t.needReadable;return p("need readable",o),(0===t.length||t.length-e0?D(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&O(this)),null!==r&&this.emit("data",r),r},m.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},m.prototype.pipe=function(e,t){var n=this,i=this._readableState;switch(i.pipesCount){case 0:i.pipes=e;break;case 1:i.pipes=[i.pipes,e];break;default:i.pipes.push(e)}i.pipesCount+=1,p("pipe count=%d opts=%j",i.pipesCount,t);var c=(!t||!1!==t.end)&&e!==r.stdout&&e!==r.stderr?l:m;function u(t,r){p("onunpipe"),t===n&&r&&!1===r.hasUnpiped&&(r.hasUnpiped=!0,p("cleanup"),e.removeListener("close",v),e.removeListener("finish",b),e.removeListener("drain",f),e.removeListener("error",y),e.removeListener("unpipe",u),n.removeListener("end",l),n.removeListener("end",m),n.removeListener("data",g),h=!0,!i.awaitDrain||e._writableState&&!e._writableState.needDrain||f())}function l(){p("onend"),e.end()}i.endEmitted?o.nextTick(c):n.once("end",c),e.on("unpipe",u);var f=function(e){return function(){var t=e._readableState;p("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&a(e,"data")&&(t.flowing=!0,R(e))}}(n);e.on("drain",f);var h=!1;var d=!1;function g(t){p("ondata"),d=!1,!1!==e.write(t)||d||((1===i.pipesCount&&i.pipes===e||i.pipesCount>1&&-1!==M(i.pipes,e))&&!h&&(p("false write response, pause",n._readableState.awaitDrain),n._readableState.awaitDrain++,d=!0),n.pause())}function y(t){p("onerror",t),m(),e.removeListener("error",y),0===a(e,"error")&&e.emit("error",t)}function v(){e.removeListener("finish",b),m()}function b(){p("onfinish"),e.removeListener("close",v),m()}function m(){p("unpipe"),n.unpipe(e)}return n.on("data",g),function(e,t,n){if("function"==typeof e.prependListener)return e.prependListener(t,n);e._events&&e._events[t]?s(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n)}(e,"error",y),e.once("close",v),e.once("finish",b),e.emit("pipe",n),i.flowing||(p("pipe resume"),n.resume()),e},m.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n),this);if(!e){var r=t.pipes,o=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var i=0;i0&&s.length>o&&!s.warned){s.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=s.length,a=c,console&&console.warn&&console.warn(a)}return e}function f(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},o=function(){for(var e=[],t=0;t0&&(s=t[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var c=o[e];if(void 0===c)return!1;if("function"==typeof c)i(c,this,t);else{var u=c.length,l=d(c,u);for(n=0;n=0;i--)if(n[i]===t||n[i].listener===t){s=n[i].listener,o=i;break}if(o<0)return this;0===o?n.shift():function(e,t){for(;t+1=0;r--)this.removeListener(e,t[r]);return this},a.prototype.listeners=function(e){return h(this,e,!0)},a.prototype.rawListeners=function(e){return h(this,e,!1)},a.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):p.call(e,t)},a.prototype.listenerCount=p,a.prototype.eventNames=function(){return this._eventsCount>0?r(this._events):[]}},function(e,t,n){e.exports=n(37).EventEmitter},function(e,t,n){"use strict";var r=n(23);function o(e,t){e.emit("error",t)}e.exports={destroy:function(e,t){var n=this,i=this._readableState&&this._readableState.destroyed,s=this._writableState&&this._writableState.destroyed;return i||s?(t?t(e):!e||this._writableState&&this._writableState.errorEmitted||r.nextTick(o,this,e),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(e){!t&&e?(r.nextTick(o,n,e),n._writableState&&(n._writableState.errorEmitted=!0)):t&&t(e)}),this)},undestroy:function(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}}},function(e,t,n){"use strict";var r=n(61).Buffer,o=r.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function i(e){var t;switch(this.encoding=function(e){var t=function(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}(e);if("string"!=typeof t&&(r.isEncoding===o||!o(e)))throw new Error("Unknown encoding: "+e);return t||e}(e),this.encoding){case"utf16le":this.text=c,this.end=u,t=4;break;case"utf8":this.fillLast=a,t=4;break;case"base64":this.text=l,this.end=f,t=3;break;default:return this.write=h,void(this.end=p)}this.lastNeed=0,this.lastTotal=0,this.lastChar=r.allocUnsafe(t)}function s(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function a(e){var t=this.lastTotal-this.lastNeed,n=function(e,t,n){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}(this,e);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function c(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function u(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function l(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function f(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function h(e){return e.toString(this.encoding)}function p(e){return e&&e.length?this.write(e):""}t.StringDecoder=i,i.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n=0)return o>0&&(e.lastNeed=o-1),o;if(--r=0)return o>0&&(e.lastNeed=o-2),o;if(--r=0)return o>0&&(2===o?o=0:e.lastNeed=o-3),o;return 0}(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)},i.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length}},function(e,t,n){"use strict";(function(t,r,o){var i=n(23);function s(e){var t=this;this.next=null,this.entry=null,this.finish=function(){!function(e,t,n){var r=e.entry;e.entry=null;for(;r;){var o=r.callback;t.pendingcb--,o(n),r=r.next}t.corkedRequestsFree?t.corkedRequestsFree.next=e:t.corkedRequestsFree=e}(t,e)}}e.exports=b;var a,c=!t.browser&&["v0.10","v0.9."].indexOf(t.version.slice(0,5))>-1?r:i.nextTick;b.WritableState=v;var u=n(19);u.inherits=n(14);var l={deprecate:n(64)},f=n(38),h=n(13).Buffer,p=o.Uint8Array||function(){};var d,g=n(39);function y(){}function v(e,t){a=a||n(11),e=e||{};var r=t instanceof a;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var o=e.highWaterMark,u=e.writableHighWaterMark,l=this.objectMode?16:16384;this.highWaterMark=o||0===o?o:r&&(u||0===u)?u:l,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var f=!1===e.decodeStrings;this.decodeStrings=!f,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var n=e._writableState,r=n.sync,o=n.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(n),t)!function(e,t,n,r,o){--t.pendingcb,n?(i.nextTick(o,r),i.nextTick(_,e,t),e._writableState.errorEmitted=!0,e.emit("error",r)):(o(r),e._writableState.errorEmitted=!0,e.emit("error",r),_(e,t))}(e,n,r,t,o);else{var s=S(n);s||n.corked||n.bufferProcessing||!n.bufferedRequest||E(e,n),r?c(w,e,n,s,o):w(e,n,s,o)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new s(this)}function b(e){if(a=a||n(11),!(d.call(b,this)||this instanceof a))return new b(e);this._writableState=new v(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),f.call(this)}function m(e,t,n,r,o,i,s){t.writelen=r,t.writecb=s,t.writing=!0,t.sync=!0,n?e._writev(o,t.onwrite):e._write(o,i,t.onwrite),t.sync=!1}function w(e,t,n,r){n||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,r(),_(e,t)}function E(e,t){t.bufferProcessing=!0;var n=t.bufferedRequest;if(e._writev&&n&&n.next){var r=t.bufferedRequestCount,o=new Array(r),i=t.corkedRequestsFree;i.entry=n;for(var a=0,c=!0;n;)o[a]=n,n.isBuf||(c=!1),n=n.next,a+=1;o.allBuffers=c,m(e,t,!0,t.length,o,"",i.finish),t.pendingcb++,t.lastBufferedRequest=null,i.next?(t.corkedRequestsFree=i.next,i.next=null):t.corkedRequestsFree=new s(t),t.bufferedRequestCount=0}else{for(;n;){var u=n.chunk,l=n.encoding,f=n.callback;if(m(e,t,!1,t.objectMode?1:u.length,u,l,f),n=n.next,t.bufferedRequestCount--,t.writing)break}null===n&&(t.lastBufferedRequest=null)}t.bufferedRequest=n,t.bufferProcessing=!1}function S(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function C(e,t){e._final(function(n){t.pendingcb--,n&&e.emit("error",n),t.prefinished=!0,e.emit("prefinish"),_(e,t)})}function _(e,t){var n=S(t);return n&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,i.nextTick(C,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),n}u.inherits(b,f),v.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(v.prototype,"buffer",{get:l.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(d=Function.prototype[Symbol.hasInstance],Object.defineProperty(b,Symbol.hasInstance,{value:function(e){return!!d.call(this,e)||this===b&&(e&&e._writableState instanceof v)}})):d=function(e){return e instanceof this},b.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},b.prototype.write=function(e,t,n){var r,o=this._writableState,s=!1,a=!o.objectMode&&(r=e,h.isBuffer(r)||r instanceof p);return a&&!h.isBuffer(e)&&(e=function(e){return h.from(e)}(e)),"function"==typeof t&&(n=t,t=null),a?t="buffer":t||(t=o.defaultEncoding),"function"!=typeof n&&(n=y),o.ended?function(e,t){var n=new Error("write after end");e.emit("error",n),i.nextTick(t,n)}(this,n):(a||function(e,t,n,r){var o=!0,s=!1;return null===n?s=new TypeError("May not write null values to stream"):"string"==typeof n||void 0===n||t.objectMode||(s=new TypeError("Invalid non-string/buffer chunk")),s&&(e.emit("error",s),i.nextTick(r,s),o=!1),o}(this,o,e,n))&&(o.pendingcb++,s=function(e,t,n,r,o,i){if(!n){var s=function(e,t,n){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=h.from(t,n));return t}(t,r,o);r!==s&&(n=!0,o="buffer",r=s)}var a=t.objectMode?1:r.length;t.length+=a;var c=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(b.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),b.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},b.prototype._writev=null,b.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!=e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||function(e,t,n){t.ending=!0,_(e,t),n&&(t.finished?i.nextTick(n):e.once("finish",n));t.ended=!0,e.writable=!1}(this,r,n)},Object.defineProperty(b.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),b.prototype.destroy=g.destroy,b.prototype._undestroy=g.undestroy,b.prototype._destroy=function(e,t){this.end(),t(e)}}).call(this,n(18),n(62).setImmediate,n(10))},function(e,t,n){"use strict";e.exports=s;var r=n(11),o=n(19);function i(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(!r)return this.emit("error",new Error("write callback called multiple times"));n.writechunk=null,n.writecb=null,null!=t&&this.push(t),r(e);var o=this._readableState;o.reading=!1,(o.needReadable||o.length=200&&c.statusCode<300?r(new s.b(c.statusCode,c.statusMessage||"",u)):o(new i.b(c.statusMessage||"",c.statusCode||0))});t.abortSignal&&(t.abortSignal.onabort=function(){f.abort(),o(new i.a)})})},n.prototype.getCookieString=function(e){return this.cookieJar.getCookieString(e)},n}(s.a)}).call(this,n(5).Buffer)},function(e,t,n){"use strict";(function(e){n.d(t,"a",function(){return i});var r=n(7),o=n(1),i=function(){function t(){}return t.prototype.writeHandshakeRequest=function(e){return r.a.write(JSON.stringify(e))},t.prototype.parseHandshakeResponse=function(t){var n,i;if(Object(o.g)(t)||void 0!==e&&t instanceof e){var s=new Uint8Array(t);if(-1===(c=s.indexOf(r.a.RecordSeparatorCode)))throw new Error("Message is incomplete.");var a=c+1;n=String.fromCharCode.apply(null,s.slice(0,a)),i=s.byteLength>a?s.slice(a).buffer:null}else{var c,u=t;if(-1===(c=u.indexOf(r.a.RecordSeparator)))throw new Error("Message is incomplete.");a=c+1;n=u.substring(0,a),i=u.length>a?u.substring(a):null}var l=r.a.parse(n),f=JSON.parse(l[0]);if(f.type)throw new Error("Expected a handshake response from the server.");return[i,f]},t}()}).call(this,n(5).Buffer)},,,,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(e){i(e)}}function a(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(s,a)}c((r=r.apply(e,t||[])).next())})},o=this&&this.__generator||function(e,t){var n,r,o,i,s={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(i){return function(a){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;s;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return s.label++,{value:i[1],done:!1};case 5:s.label++,r=i[1],i=[0];continue;case 7:i=s.ops.pop(),s.trys.pop();continue;default:if(!(o=(o=s.trys).length>0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0)&&!(r=i.next()).done;)s.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=i.return)&&n.call(i)}finally{if(o)throw o.error}}return s},s=this&&this.__spread||function(){for(var e=[],t=0;t0?r-4:r,f=0;f>16&255,a[c++]=t>>8&255,a[c++]=255&t;2===s&&(t=o[e.charCodeAt(f)]<<2|o[e.charCodeAt(f+1)]>>4,a[c++]=255&t);1===s&&(t=o[e.charCodeAt(f)]<<10|o[e.charCodeAt(f+1)]<<4|o[e.charCodeAt(f+2)]>>2,a[c++]=t>>8&255,a[c++]=255&t);return a},t.fromByteArray=function(e){for(var t,n=e.length,o=n%3,i=[],s=0,a=n-o;sa?a:s+16383));1===o?(t=e[n-1],i.push(r[t>>2]+r[t<<4&63]+"==")):2===o&&(t=(e[n-2]<<8)+e[n-1],i.push(r[t>>10]+r[t>>4&63]+r[t<<2&63]+"="));return i.join("")};for(var r=[],o=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=0,c=s.length;a0)throw new Error("Invalid string. Length must be a multiple of 4");var n=e.indexOf("=");return-1===n&&(n=t),[n,n===t?0:4-n%4]}function l(e,t,n){for(var o,i,s=[],a=t;a>18&63]+r[i>>12&63]+r[i>>6&63]+r[63&i]);return s.join("")}o["-".charCodeAt(0)]=62,o["_".charCodeAt(0)]=63},function(e,t){t.read=function(e,t,n,r,o){var i,s,a=8*o-r-1,c=(1<>1,l=-7,f=n?o-1:0,h=n?-1:1,p=e[t+f];for(f+=h,i=p&(1<<-l)-1,p>>=-l,l+=a;l>0;i=256*i+e[t+f],f+=h,l-=8);for(s=i&(1<<-l)-1,i>>=-l,l+=r;l>0;s=256*s+e[t+f],f+=h,l-=8);if(0===i)i=1-u;else{if(i===c)return s?NaN:1/0*(p?-1:1);s+=Math.pow(2,r),i-=u}return(p?-1:1)*s*Math.pow(2,i-r)},t.write=function(e,t,n,r,o,i){var s,a,c,u=8*i-o-1,l=(1<>1,h=23===o?Math.pow(2,-24)-Math.pow(2,-77):0,p=r?0:i-1,d=r?1:-1,g=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(a=isNaN(t)?1:0,s=l):(s=Math.floor(Math.log(t)/Math.LN2),t*(c=Math.pow(2,-s))<1&&(s--,c*=2),(t+=s+f>=1?h/c:h*Math.pow(2,1-f))*c>=2&&(s++,c/=2),s+f>=l?(a=0,s=l):s+f>=1?(a=(t*c-1)*Math.pow(2,o),s+=f):(a=t*Math.pow(2,f-1)*Math.pow(2,o),s=0));o>=8;e[n+p]=255&a,p+=d,a/=256,o-=8);for(s=s<0;e[n+p]=255&s,p+=d,s/=256,u-=8);e[n+p-d]|=128*g}},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t,n){"use strict";(function(t){ +var r=n(50),o=n(51),i=n(52);function a(){return c.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function d(e,t){if(c.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return F(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return H(e).length;default:if(r)return F(e).length;t=(""+t).toLowerCase(),r=!0}}function g(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function y(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=c.from(t,r)),c.isBuffer(t))return 0===t.length?-1:v(e,t,n,r,o);if("number"==typeof t)return t&=255,c.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):v(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function v(e,t,n,r,o){var i,a=1,s=e.length,c=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,c/=2,n/=2}function u(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(o){var l=-1;for(i=n;is&&(n=s-c),i=n;i>=0;i--){for(var f=!0,h=0;ho&&(r=o):r=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");r>i/2&&(r=i/2);for(var a=0;a>8,o=n%256,i.push(o),i.push(r);return i}(t,e.length-n),e,n,r)}function _(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function I(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:u>223?3:u>191?2:1;if(o+f<=n)switch(f){case 1:u<128&&(l=u);break;case 2:128==(192&(i=e[o+1]))&&(c=(31&u)<<6|63&i)>127&&(l=c);break;case 3:i=e[o+1],a=e[o+2],128==(192&i)&&128==(192&a)&&(c=(15&u)<<12|(63&i)<<6|63&a)>2047&&(c<55296||c>57343)&&(l=c);break;case 4:i=e[o+1],a=e[o+2],s=e[o+3],128==(192&i)&&128==(192&a)&&128==(192&s)&&(c=(15&u)<<18|(63&i)<<12|(63&a)<<6|63&s)>65535&&c<1114112&&(l=c)}null===l?(l=65533,f=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),o+=f}return function(e){var t=e.length;if(t<=T)return String.fromCharCode.apply(String,e);var n="",r=0;for(;rthis.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return x(this,t,n);case"utf8":case"utf-8":return I(this,t,n);case"ascii":return k(this,t,n);case"latin1":case"binary":return P(this,t,n);case"base64":return _(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return R(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}.apply(this,arguments)},c.prototype.equals=function(e){if(!c.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===c.compare(this,e)},c.prototype.inspect=function(){var e="",n=t.INSPECT_MAX_BYTES;return this.length>0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},c.prototype.compare=function(e,t,n,r,o){if(!c.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(this===e)return 0;for(var i=(o>>>=0)-(r>>>=0),a=(n>>>=0)-(t>>>=0),s=Math.min(i,a),u=this.slice(r,o),l=e.slice(t,n),f=0;fo)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var i=!1;;)switch(r){case"hex":return b(this,e,t,n);case"utf8":case"utf-8":return m(this,e,t,n);case"ascii":return w(this,e,t,n);case"latin1":case"binary":return E(this,e,t,n);case"base64":return S(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return C(this,e,t,n);default:if(i)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),i=!0}},c.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var T=4096;function k(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",i=t;in)throw new RangeError("Trying to access beyond buffer length")}function O(e,t,n,r,o,i){if(!c.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function L(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function M(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function A(e,t,n,r,o,i){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function B(e,t,n,r,i){return i||A(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function j(e,t,n,r,i){return i||A(e,0,n,8),o.write(e,t,n,r,52,8),n+8}c.prototype.slice=function(e,t){var n,r=this.length;if((e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},c.prototype.readUInt8=function(e,t){return t||D(e,1,this.length),this[e]},c.prototype.readUInt16LE=function(e,t){return t||D(e,2,this.length),this[e]|this[e+1]<<8},c.prototype.readUInt16BE=function(e,t){return t||D(e,2,this.length),this[e]<<8|this[e+1]},c.prototype.readUInt32LE=function(e,t){return t||D(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},c.prototype.readUInt32BE=function(e,t){return t||D(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},c.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||D(e,t,this.length);for(var r=this[e],o=1,i=0;++i=(o*=128)&&(r-=Math.pow(2,8*t)),r},c.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||D(e,t,this.length);for(var r=t,o=1,i=this[e+--r];r>0&&(o*=256);)i+=this[e+--r]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},c.prototype.readInt8=function(e,t){return t||D(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},c.prototype.readInt16LE=function(e,t){t||D(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt16BE=function(e,t){t||D(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},c.prototype.readInt32LE=function(e,t){return t||D(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},c.prototype.readInt32BE=function(e,t){return t||D(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},c.prototype.readFloatLE=function(e,t){return t||D(e,4,this.length),o.read(this,e,!0,23,4)},c.prototype.readFloatBE=function(e,t){return t||D(e,4,this.length),o.read(this,e,!1,23,4)},c.prototype.readDoubleLE=function(e,t){return t||D(e,8,this.length),o.read(this,e,!0,52,8)},c.prototype.readDoubleBE=function(e,t){return t||D(e,8,this.length),o.read(this,e,!1,52,8)},c.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||O(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+n},c.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,1,255,0),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},c.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):L(this,e,t,!0),t+2},c.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):L(this,e,t,!1),t+2},c.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):M(this,e,t,!0),t+4},c.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):M(this,e,t,!1),t+4},c.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);O(this,e,t,n,o-1,-o)}var i=0,a=1,s=0;for(this[t]=255&e;++i>0)-s&255;return t+n},c.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);O(this,e,t,n,o-1,-o)}var i=n-1,a=1,s=0;for(this[t+i]=255&e;--i>=0&&(a*=256);)e<0&&0===s&&0!==this[t+i+1]&&(s=1),this[t+i]=(e/a>>0)-s&255;return t+n},c.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,1,127,-128),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},c.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):L(this,e,t,!0),t+2},c.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):L(this,e,t,!1),t+2},c.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,2147483647,-2147483648),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):M(this,e,t,!0),t+4},c.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):M(this,e,t,!1),t+4},c.prototype.writeFloatLE=function(e,t,n){return B(this,e,t,!0,n)},c.prototype.writeFloatBE=function(e,t,n){return B(this,e,t,!1,n)},c.prototype.writeDoubleLE=function(e,t,n){return j(this,e,t,!0,n)},c.prototype.writeDoubleBE=function(e,t,n){return j(this,e,t,!1,n)},c.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(i<1e3||!c.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&i.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&i.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;i.push(n)}else if(n<2048){if((t-=2)<0)break;i.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;i.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return i}function H(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(U,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function q(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(this,n(10))},function(e,t,n){"use strict";n.d(t,"a",function(){return r});var r=function(){function e(){}return e.prototype.log=function(e,t){},e.instance=new e,e}()},function(e,t,n){"use strict";n.d(t,"a",function(){return r});var r=function(){function e(){}return e.write=function(t){return""+t+e.RecordSeparator},e.parse=function(t){if(t[t.length-1]!==e.RecordSeparator)throw new Error("Message is incomplete.");var n=t.split(e.RecordSeparator);return n.pop(),n},e.RecordSeparatorCode=30,e.RecordSeparator=String.fromCharCode(e.RecordSeparatorCode),e}()},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(25),n(9);var r=n(26),o=n(16),i={},a=!1;function s(e,t,n){var o=i[e];o||(o=i[e]=new r.BrowserRenderer(e)),o.attachRootComponentToLogicalElement(n,t)}t.attachRootComponentToLogicalElement=s,t.attachRootComponentToElement=function(e,t,n){var r=document.querySelector(e);if(!r)throw new Error("Could not find any element matching selector '"+e+"'.");s(n||0,o.toLogicalElement(r,!0),t)},t.renderBatch=function(e,t){var n=i[e];if(!n)throw new Error("There is no browser renderer with ID "+e+".");for(var r=t.arrayRangeReader,o=t.updatedComponents(),s=r.values(o),c=r.count(o),u=t.referenceFrames(),l=r.values(u),f=t.diffReader,h=0;h=0,"must have a non-negative type"),o(a,"must have a decode function"),this.registerEncoder(function(e){return e instanceof t},function(t){var o=i(),a=r.allocUnsafe(1);return a.writeInt8(e,0),o.append(a),o.append(n(t)),o}),this.registerDecoder(e,a),this},registerEncoder:function(e,n){return o(e,"must have an encode function"),o(n,"must have an encode function"),t.push({check:e,encode:n}),this},registerDecoder:function(e,t){return o(e>=0,"must have a non-negative type"),o(t,"must have a decode function"),n.push({type:e,decode:t}),this},encoder:a.encoder,decoder:a.decoder,buffer:!0,type:"msgpack5",IncompleteBufferError:s.IncompleteBufferError}}},function(e,t,n){var r=n(5),o=r.Buffer;function i(e,t){for(var n in e)t[n]=e[n]}function a(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=a),i(o,a),a.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},a.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},a.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},a.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){"use strict";var r;!function(e){window.DotNet=e;var t=[],n={},r={},o=1,i=null;function a(e){t.push(e)}function s(e,t){for(var n=[],r=2;r0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return e[r]=[],e}function s(e,t,n){var i=e;if(e instanceof Comment&&(u(i)&&u(i).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(c(i))throw new Error("Not implemented: moving existing logical children");var a=u(t);if(n0;)e(r,0);var i=r;i.parentNode.removeChild(i)},t.getLogicalParent=c,t.getLogicalSiblingEnd=function(e){return e[i]||null},t.getLogicalChild=function(e,t){return u(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===l(e).namespaceURI},t.getLogicalChildrenArray=u,t.permuteLogicalChildren=function(e,t){var n=u(e);t.forEach(function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=c(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)}),t.forEach(function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):h(r,e)}),t.forEach(function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,i=r;i;){var a=i.nextSibling;if(n.insertBefore(i,t),i===o)break;i=a}n.removeChild(t)}),t.forEach(function(e){n[e.toSiblingIndex]=e.moveRangeStart})},t.getClosestDomElement=l},function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),t.dispatchEvent=function(e,t){if(!r)throw new Error("eventDispatcher not initialized. Call 'setEventDispatcher' to configure it.");return r(e,t)},t.setEventDispatcher=function(e){r=e}},function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function s(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:a}catch(e){r=a}}();var c,u=[],l=!1,f=-1;function h(){l&&c&&(l=!1,c.length?u=c.concat(u):f=-1,u.length&&p())}function p(){if(!l){var e=s(h);l=!0;for(var t=u.length;t;){for(c=u,u=[];++f1)for(var n=1;n0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]this.length)&&(r=this.length),n>=this.length)return e||i.alloc(0);if(r<=0)return e||i.alloc(0);var o,a,s=!!e,c=this._offset(n),u=r-n,l=u,f=s&&t||0,h=c[1];if(0===n&&r==this.length){if(!s)return 1===this._bufs.length?this._bufs[0]:i.concat(this._bufs,this.length);for(a=0;a(o=this._bufs[a].length-h))){this._bufs[a].copy(e,f,h,h+l);break}this._bufs[a].copy(e,f,h),f+=o,l-=o,h&&(h=0)}return e},a.prototype.shallowSlice=function(e,t){e=e||0,t=t||this.length,e<0&&(e+=this.length),t<0&&(t+=this.length);var n=this._offset(e),r=this._offset(t),o=this._bufs.slice(n[0],r[0]+1);return 0==r[1]?o.pop():o[o.length-1]=o[o.length-1].slice(0,r[1]),0!=n[1]&&(o[0]=o[0].slice(n[1])),new a(o)},a.prototype.toString=function(e,t,n){return this.slice(t,n).toString(e)},a.prototype.consume=function(e){for(;this._bufs.length;){if(!(e>=this._bufs[0].length)){this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift()}return this},a.prototype.duplicate=function(){for(var e=0,t=new a;e0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]=i)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(e){return"[Circular]"}default:return e}}),c=r[n];n=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),d(n)?r.showHidden=n:n&&t._extend(r,n),b(r.showHidden)&&(r.showHidden=!1),b(r.depth)&&(r.depth=2),b(r.colors)&&(r.colors=!1),b(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=c),l(r,e,r.depth)}function c(e,t){var n=s.styles[t];return n?"["+s.colors[n][0]+"m"+e+"["+s.colors[n][1]+"m":e}function u(e,t){return e}function l(e,n,r){if(e.customInspect&&n&&C(n.inspect)&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var o=n.inspect(r,e);return v(o)||(o=l(e,o,r)),o}var i=function(e,t){if(b(t))return e.stylize("undefined","undefined");if(v(t)){var n="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(n,"string")}if(y(t))return e.stylize(""+t,"number");if(d(t))return e.stylize(""+t,"boolean");if(g(t))return e.stylize("null","null")}(e,n);if(i)return i;var a=Object.keys(n),s=function(e){var t={};return e.forEach(function(e,n){t[e]=!0}),t}(a);if(e.showHidden&&(a=Object.getOwnPropertyNames(n)),S(n)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return f(n);if(0===a.length){if(C(n)){var c=n.name?": "+n.name:"";return e.stylize("[Function"+c+"]","special")}if(m(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(E(n))return e.stylize(Date.prototype.toString.call(n),"date");if(S(n))return f(n)}var u,w="",_=!1,I=["{","}"];(p(n)&&(_=!0,I=["[","]"]),C(n))&&(w=" [Function"+(n.name?": "+n.name:"")+"]");return m(n)&&(w=" "+RegExp.prototype.toString.call(n)),E(n)&&(w=" "+Date.prototype.toUTCString.call(n)),S(n)&&(w=" "+f(n)),0!==a.length||_&&0!=n.length?r<0?m(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special"):(e.seen.push(n),u=_?function(e,t,n,r,o){for(var i=[],a=0,s=t.length;a=0&&0,e+t.replace(/\u001b\[\d\d?m/g,"").length+1},0)>60)return n[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+n[1];return n[0]+t+" "+e.join(", ")+" "+n[1]}(u,w,I)):I[0]+w+I[1]}function f(e){return"["+Error.prototype.toString.call(e)+"]"}function h(e,t,n,r,o,i){var a,s,c;if((c=Object.getOwnPropertyDescriptor(t,o)||{value:t[o]}).get?s=c.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):c.set&&(s=e.stylize("[Setter]","special")),k(r,o)||(a="["+o+"]"),s||(e.seen.indexOf(c.value)<0?(s=g(n)?l(e,c.value,null):l(e,c.value,n-1)).indexOf("\n")>-1&&(s=i?s.split("\n").map(function(e){return" "+e}).join("\n").substr(2):"\n"+s.split("\n").map(function(e){return" "+e}).join("\n")):s=e.stylize("[Circular]","special")),b(a)){if(i&&o.match(/^\d+$/))return s;(a=JSON.stringify(""+o)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=e.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=e.stylize(a,"string"))}return a+": "+s}function p(e){return Array.isArray(e)}function d(e){return"boolean"==typeof e}function g(e){return null===e}function y(e){return"number"==typeof e}function v(e){return"string"==typeof e}function b(e){return void 0===e}function m(e){return w(e)&&"[object RegExp]"===_(e)}function w(e){return"object"==typeof e&&null!==e}function E(e){return w(e)&&"[object Date]"===_(e)}function S(e){return w(e)&&("[object Error]"===_(e)||e instanceof Error)}function C(e){return"function"==typeof e}function _(e){return Object.prototype.toString.call(e)}function I(e){return e<10?"0"+e.toString(10):e.toString(10)}t.debuglog=function(n){if(b(i)&&(i=e.env.NODE_DEBUG||""),n=n.toUpperCase(),!a[n])if(new RegExp("\\b"+n+"\\b","i").test(i)){var r=e.pid;a[n]=function(){var e=t.format.apply(t,arguments);console.error("%s %d: %s",n,r,e)}}else a[n]=function(){};return a[n]},t.inspect=s,s.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},s.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},t.isArray=p,t.isBoolean=d,t.isNull=g,t.isNullOrUndefined=function(e){return null==e},t.isNumber=y,t.isString=v,t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=b,t.isRegExp=m,t.isObject=w,t.isDate=E,t.isError=S,t.isFunction=C,t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=n(54);var T=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function k(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.log=function(){var e,n;console.log("%s - %s",(e=new Date,n=[I(e.getHours()),I(e.getMinutes()),I(e.getSeconds())].join(":"),[e.getDate(),T[e.getMonth()],n].join(" ")),t.format.apply(t,arguments))},t.inherits=n(55),t._extend=function(e,t){if(!t||!w(t))return e;for(var n=Object.keys(t),r=n.length;r--;)e[n[r]]=t[n[r]];return e};var P="undefined"!=typeof Symbol?Symbol("util.promisify.custom"):void 0;function x(e,t){if(!e){var n=new Error("Promise was rejected with a falsy value");n.reason=e,e=n}return t(e)}t.promisify=function(e){if("function"!=typeof e)throw new TypeError('The "original" argument must be of type Function');if(P&&e[P]){var t;if("function"!=typeof(t=e[P]))throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,P,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var t,n,r=new Promise(function(e,r){t=e,n=r}),o=[],i=0;i0?("string"==typeof t||a.objectMode||Object.getPrototypeOf(t)===u.prototype||(t=function(e){return u.from(e)}(t)),r?a.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):E(e,a,t,!0):a.ended?e.emit("error",new Error("stream.push() after EOF")):(a.reading=!1,a.decoder&&!n?(t=a.decoder.write(t),a.objectMode||0!==t.length?E(e,a,t,!1):T(e,a)):E(e,a,t,!1))):r||(a.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=S?e=S:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function _(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(p("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?o.nextTick(I,e):I(e))}function I(e){p("emit readable"),e.emit("readable"),R(e)}function T(e,t){t.readingMore||(t.readingMore=!0,o.nextTick(k,e,t))}function k(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=function(e,t,n){var r;ei.length?i.length:e;if(a===i.length?o+=i:o+=i.slice(0,e),0===(e-=a)){a===i.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=i.slice(a));break}++r}return t.length-=r,o}(e,t):function(e,t){var n=u.allocUnsafe(e),r=t.head,o=1;r.data.copy(n),e-=r.data.length;for(;r=r.next;){var i=r.data,a=e>i.length?i.length:e;if(i.copy(n,n.length-e,0,a),0===(e-=a)){a===i.length?(++o,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=i.slice(a));break}++o}return t.length-=o,n}(e,t);return r}(e,t.buffer,t.decoder),n);var n}function O(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,o.nextTick(L,t,e))}function L(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function M(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return p("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?O(this):_(this),null;if(0===(e=C(e,t))&&t.ended)return 0===t.length&&O(this),null;var r,o=t.needReadable;return p("need readable",o),(0===t.length||t.length-e0?D(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&O(this)),null!==r&&this.emit("data",r),r},m.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},m.prototype.pipe=function(e,t){var n=this,i=this._readableState;switch(i.pipesCount){case 0:i.pipes=e;break;case 1:i.pipes=[i.pipes,e];break;default:i.pipes.push(e)}i.pipesCount+=1,p("pipe count=%d opts=%j",i.pipesCount,t);var c=(!t||!1!==t.end)&&e!==r.stdout&&e!==r.stderr?l:m;function u(t,r){p("onunpipe"),t===n&&r&&!1===r.hasUnpiped&&(r.hasUnpiped=!0,p("cleanup"),e.removeListener("close",v),e.removeListener("finish",b),e.removeListener("drain",f),e.removeListener("error",y),e.removeListener("unpipe",u),n.removeListener("end",l),n.removeListener("end",m),n.removeListener("data",g),h=!0,!i.awaitDrain||e._writableState&&!e._writableState.needDrain||f())}function l(){p("onend"),e.end()}i.endEmitted?o.nextTick(c):n.once("end",c),e.on("unpipe",u);var f=function(e){return function(){var t=e._readableState;p("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&s(e,"data")&&(t.flowing=!0,R(e))}}(n);e.on("drain",f);var h=!1;var d=!1;function g(t){p("ondata"),d=!1,!1!==e.write(t)||d||((1===i.pipesCount&&i.pipes===e||i.pipesCount>1&&-1!==M(i.pipes,e))&&!h&&(p("false write response, pause",n._readableState.awaitDrain),n._readableState.awaitDrain++,d=!0),n.pause())}function y(t){p("onerror",t),m(),e.removeListener("error",y),0===s(e,"error")&&e.emit("error",t)}function v(){e.removeListener("finish",b),m()}function b(){p("onfinish"),e.removeListener("close",v),m()}function m(){p("unpipe"),n.unpipe(e)}return n.on("data",g),function(e,t,n){if("function"==typeof e.prependListener)return e.prependListener(t,n);e._events&&e._events[t]?a(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n)}(e,"error",y),e.once("close",v),e.once("finish",b),e.emit("pipe",n),i.flowing||(p("pipe resume"),n.resume()),e},m.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n),this);if(!e){var r=t.pipes,o=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var i=0;i0&&a.length>o&&!a.warned){a.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=a.length,s=c,console&&console.warn&&console.warn(s)}return e}function f(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},o=function(){for(var e=[],t=0;t0&&(a=t[0]),a instanceof Error)throw a;var s=new Error("Unhandled error."+(a?" ("+a.message+")":""));throw s.context=a,s}var c=o[e];if(void 0===c)return!1;if("function"==typeof c)i(c,this,t);else{var u=c.length,l=d(c,u);for(n=0;n=0;i--)if(n[i]===t||n[i].listener===t){a=n[i].listener,o=i;break}if(o<0)return this;0===o?n.shift():function(e,t){for(;t+1=0;r--)this.removeListener(e,t[r]);return this},s.prototype.listeners=function(e){return h(this,e,!0)},s.prototype.rawListeners=function(e){return h(this,e,!1)},s.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):p.call(e,t)},s.prototype.listenerCount=p,s.prototype.eventNames=function(){return this._eventsCount>0?r(this._events):[]}},function(e,t,n){e.exports=n(37).EventEmitter},function(e,t,n){"use strict";var r=n(23);function o(e,t){e.emit("error",t)}e.exports={destroy:function(e,t){var n=this,i=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return i||a?(t?t(e):!e||this._writableState&&this._writableState.errorEmitted||r.nextTick(o,this,e),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(e){!t&&e?(r.nextTick(o,n,e),n._writableState&&(n._writableState.errorEmitted=!0)):t&&t(e)}),this)},undestroy:function(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}}},function(e,t,n){"use strict";var r=n(61).Buffer,o=r.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function i(e){var t;switch(this.encoding=function(e){var t=function(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}(e);if("string"!=typeof t&&(r.isEncoding===o||!o(e)))throw new Error("Unknown encoding: "+e);return t||e}(e),this.encoding){case"utf16le":this.text=c,this.end=u,t=4;break;case"utf8":this.fillLast=s,t=4;break;case"base64":this.text=l,this.end=f,t=3;break;default:return this.write=h,void(this.end=p)}this.lastNeed=0,this.lastTotal=0,this.lastChar=r.allocUnsafe(t)}function a(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function s(e){var t=this.lastTotal-this.lastNeed,n=function(e,t,n){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}(this,e);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function c(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function u(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function l(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function f(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function h(e){return e.toString(this.encoding)}function p(e){return e&&e.length?this.write(e):""}t.StringDecoder=i,i.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n=0)return o>0&&(e.lastNeed=o-1),o;if(--r=0)return o>0&&(e.lastNeed=o-2),o;if(--r=0)return o>0&&(2===o?o=0:e.lastNeed=o-3),o;return 0}(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)},i.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length}},function(e,t,n){"use strict";(function(t,r,o){var i=n(23);function a(e){var t=this;this.next=null,this.entry=null,this.finish=function(){!function(e,t,n){var r=e.entry;e.entry=null;for(;r;){var o=r.callback;t.pendingcb--,o(n),r=r.next}t.corkedRequestsFree?t.corkedRequestsFree.next=e:t.corkedRequestsFree=e}(t,e)}}e.exports=b;var s,c=!t.browser&&["v0.10","v0.9."].indexOf(t.version.slice(0,5))>-1?r:i.nextTick;b.WritableState=v;var u=n(19);u.inherits=n(14);var l={deprecate:n(64)},f=n(38),h=n(13).Buffer,p=o.Uint8Array||function(){};var d,g=n(39);function y(){}function v(e,t){s=s||n(11),e=e||{};var r=t instanceof s;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var o=e.highWaterMark,u=e.writableHighWaterMark,l=this.objectMode?16:16384;this.highWaterMark=o||0===o?o:r&&(u||0===u)?u:l,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var f=!1===e.decodeStrings;this.decodeStrings=!f,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var n=e._writableState,r=n.sync,o=n.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(n),t)!function(e,t,n,r,o){--t.pendingcb,n?(i.nextTick(o,r),i.nextTick(_,e,t),e._writableState.errorEmitted=!0,e.emit("error",r)):(o(r),e._writableState.errorEmitted=!0,e.emit("error",r),_(e,t))}(e,n,r,t,o);else{var a=S(n);a||n.corked||n.bufferProcessing||!n.bufferedRequest||E(e,n),r?c(w,e,n,a,o):w(e,n,a,o)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new a(this)}function b(e){if(s=s||n(11),!(d.call(b,this)||this instanceof s))return new b(e);this._writableState=new v(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),f.call(this)}function m(e,t,n,r,o,i,a){t.writelen=r,t.writecb=a,t.writing=!0,t.sync=!0,n?e._writev(o,t.onwrite):e._write(o,i,t.onwrite),t.sync=!1}function w(e,t,n,r){n||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,r(),_(e,t)}function E(e,t){t.bufferProcessing=!0;var n=t.bufferedRequest;if(e._writev&&n&&n.next){var r=t.bufferedRequestCount,o=new Array(r),i=t.corkedRequestsFree;i.entry=n;for(var s=0,c=!0;n;)o[s]=n,n.isBuf||(c=!1),n=n.next,s+=1;o.allBuffers=c,m(e,t,!0,t.length,o,"",i.finish),t.pendingcb++,t.lastBufferedRequest=null,i.next?(t.corkedRequestsFree=i.next,i.next=null):t.corkedRequestsFree=new a(t),t.bufferedRequestCount=0}else{for(;n;){var u=n.chunk,l=n.encoding,f=n.callback;if(m(e,t,!1,t.objectMode?1:u.length,u,l,f),n=n.next,t.bufferedRequestCount--,t.writing)break}null===n&&(t.lastBufferedRequest=null)}t.bufferedRequest=n,t.bufferProcessing=!1}function S(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function C(e,t){e._final(function(n){t.pendingcb--,n&&e.emit("error",n),t.prefinished=!0,e.emit("prefinish"),_(e,t)})}function _(e,t){var n=S(t);return n&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,i.nextTick(C,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),n}u.inherits(b,f),v.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(v.prototype,"buffer",{get:l.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(d=Function.prototype[Symbol.hasInstance],Object.defineProperty(b,Symbol.hasInstance,{value:function(e){return!!d.call(this,e)||this===b&&(e&&e._writableState instanceof v)}})):d=function(e){return e instanceof this},b.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},b.prototype.write=function(e,t,n){var r,o=this._writableState,a=!1,s=!o.objectMode&&(r=e,h.isBuffer(r)||r instanceof p);return s&&!h.isBuffer(e)&&(e=function(e){return h.from(e)}(e)),"function"==typeof t&&(n=t,t=null),s?t="buffer":t||(t=o.defaultEncoding),"function"!=typeof n&&(n=y),o.ended?function(e,t){var n=new Error("write after end");e.emit("error",n),i.nextTick(t,n)}(this,n):(s||function(e,t,n,r){var o=!0,a=!1;return null===n?a=new TypeError("May not write null values to stream"):"string"==typeof n||void 0===n||t.objectMode||(a=new TypeError("Invalid non-string/buffer chunk")),a&&(e.emit("error",a),i.nextTick(r,a),o=!1),o}(this,o,e,n))&&(o.pendingcb++,a=function(e,t,n,r,o,i){if(!n){var a=function(e,t,n){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=h.from(t,n));return t}(t,r,o);r!==a&&(n=!0,o="buffer",r=a)}var s=t.objectMode?1:r.length;t.length+=s;var c=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(b.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),b.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},b.prototype._writev=null,b.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!=e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||function(e,t,n){t.ending=!0,_(e,t),n&&(t.finished?i.nextTick(n):e.once("finish",n));t.ended=!0,e.writable=!1}(this,r,n)},Object.defineProperty(b.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),b.prototype.destroy=g.destroy,b.prototype._undestroy=g.undestroy,b.prototype._destroy=function(e,t){this.end(),t(e)}}).call(this,n(18),n(62).setImmediate,n(10))},function(e,t,n){"use strict";e.exports=a;var r=n(11),o=n(19);function i(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(!r)return this.emit("error",new Error("write callback called multiple times"));n.writechunk=null,n.writecb=null,null!=t&&this.push(t),r(e);var o=this._readableState;o.reading=!1,(o.needReadable||o.length=200&&c.statusCode<300?r(new a.b(c.statusCode,c.statusMessage||"",u)):o(new i.b(c.statusMessage||"",c.statusCode||0))});t.abortSignal&&(t.abortSignal.onabort=function(){f.abort(),o(new i.a)})})},n.prototype.getCookieString=function(e){return this.cookieJar.getCookieString(e)},n}(a.a)}).call(this,n(5).Buffer)},function(e,t,n){"use strict";(function(e){n.d(t,"a",function(){return i});var r=n(7),o=n(1),i=function(){function t(){}return t.prototype.writeHandshakeRequest=function(e){return r.a.write(JSON.stringify(e))},t.prototype.parseHandshakeResponse=function(t){var n,i;if(Object(o.g)(t)||void 0!==e&&t instanceof e){var a=new Uint8Array(t);if(-1===(c=a.indexOf(r.a.RecordSeparatorCode)))throw new Error("Message is incomplete.");var s=c+1;n=String.fromCharCode.apply(null,a.slice(0,s)),i=a.byteLength>s?a.slice(s).buffer:null}else{var c,u=t;if(-1===(c=u.indexOf(r.a.RecordSeparator)))throw new Error("Message is incomplete.");s=c+1;n=u.substring(0,s),i=u.length>s?u.substring(s):null}var l=r.a.parse(n),f=JSON.parse(l[0]);if(f.type)throw new Error("Expected a handshake response from the server.");return[i,f]},t}()}).call(this,n(5).Buffer)},,,,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,i){function a(e){try{c(r.next(e))}catch(e){i(e)}}function s(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(a,s)}c((r=r.apply(e,t||[])).next())})},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=(o=a.trys).length>0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0)&&!(r=i.next()).done;)a.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=i.return)&&n.call(i)}finally{if(o)throw o.error}}return a},a=this&&this.__spread||function(){for(var e=[],t=0;t0?r-4:r,f=0;f>16&255,s[c++]=t>>8&255,s[c++]=255&t;2===a&&(t=o[e.charCodeAt(f)]<<2|o[e.charCodeAt(f+1)]>>4,s[c++]=255&t);1===a&&(t=o[e.charCodeAt(f)]<<10|o[e.charCodeAt(f+1)]<<4|o[e.charCodeAt(f+2)]>>2,s[c++]=t>>8&255,s[c++]=255&t);return s},t.fromByteArray=function(e){for(var t,n=e.length,o=n%3,i=[],a=0,s=n-o;as?s:a+16383));1===o?(t=e[n-1],i.push(r[t>>2]+r[t<<4&63]+"==")):2===o&&(t=(e[n-2]<<8)+e[n-1],i.push(r[t>>10]+r[t>>4&63]+r[t<<2&63]+"="));return i.join("")};for(var r=[],o=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s=0,c=a.length;s0)throw new Error("Invalid string. Length must be a multiple of 4");var n=e.indexOf("=");return-1===n&&(n=t),[n,n===t?0:4-n%4]}function l(e,t,n){for(var o,i,a=[],s=t;s>18&63]+r[i>>12&63]+r[i>>6&63]+r[63&i]);return a.join("")}o["-".charCodeAt(0)]=62,o["_".charCodeAt(0)]=63},function(e,t){t.read=function(e,t,n,r,o){var i,a,s=8*o-r-1,c=(1<>1,l=-7,f=n?o-1:0,h=n?-1:1,p=e[t+f];for(f+=h,i=p&(1<<-l)-1,p>>=-l,l+=s;l>0;i=256*i+e[t+f],f+=h,l-=8);for(a=i&(1<<-l)-1,i>>=-l,l+=r;l>0;a=256*a+e[t+f],f+=h,l-=8);if(0===i)i=1-u;else{if(i===c)return a?NaN:1/0*(p?-1:1);a+=Math.pow(2,r),i-=u}return(p?-1:1)*a*Math.pow(2,i-r)},t.write=function(e,t,n,r,o,i){var a,s,c,u=8*i-o-1,l=(1<>1,h=23===o?Math.pow(2,-24)-Math.pow(2,-77):0,p=r?0:i-1,d=r?1:-1,g=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,a=l):(a=Math.floor(Math.log(t)/Math.LN2),t*(c=Math.pow(2,-a))<1&&(a--,c*=2),(t+=a+f>=1?h/c:h*Math.pow(2,1-f))*c>=2&&(a++,c/=2),a+f>=l?(s=0,a=l):a+f>=1?(s=(t*c-1)*Math.pow(2,o),a+=f):(s=t*Math.pow(2,f-1)*Math.pow(2,o),a=0));o>=8;e[n+p]=255&s,p+=d,s/=256,o-=8);for(a=a<0;e[n+p]=255&a,p+=d,a/=256,u-=8);e[n+p-d]|=128*g}},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t,n){"use strict";(function(t){ /*! * The buffer module from node.js, for the browser. * * @author Feross Aboukhadijeh * @license MIT */ -function r(e,t){if(e===t)return 0;for(var n=e.length,r=t.length,o=0,i=Math.min(n,r);o=0;u--)if(l[u]!==f[u])return!1;for(u=l.length-1;u>=0;u--)if(c=l[u],!b(e[c],t[c],n,r))return!1;return!0}(e,t,n,s))}return n?e===t:e==t}function m(e){return"[object Arguments]"==Object.prototype.toString.call(e)}function w(e,t){if(!e||!t)return!1;if("[object RegExp]"==Object.prototype.toString.call(t))return t.test(e);try{if(e instanceof t)return!0}catch(e){}return!Error.isPrototypeOf(t)&&!0===t.call({},e)}function E(e,t,n,r){var o;if("function"!=typeof t)throw new TypeError('"block" argument must be a function');"string"==typeof n&&(r=n,n=null),o=function(e){var t;try{e()}catch(e){t=e}return t}(t),r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),e&&!o&&y(o,n,"Missing expected exception"+r);var s="string"==typeof r,a=!e&&o&&!n;if((!e&&i.isError(o)&&s&&w(o,n)||a)&&y(o,n,"Got unwanted exception"+r),e&&o&&n&&!w(o,n)||!e&&o)throw o}f.AssertionError=function(e){var t;this.name="AssertionError",this.actual=e.actual,this.expected=e.expected,this.operator=e.operator,e.message?(this.message=e.message,this.generatedMessage=!1):(this.message=d(g((t=this).actual),128)+" "+t.operator+" "+d(g(t.expected),128),this.generatedMessage=!0);var n=e.stackStartFunction||y;if(Error.captureStackTrace)Error.captureStackTrace(this,n);else{var r=new Error;if(r.stack){var o=r.stack,i=p(n),s=o.indexOf("\n"+i);if(s>=0){var a=o.indexOf("\n",s+1);o=o.substring(a+1)}this.stack=o}}},i.inherits(f.AssertionError,Error),f.fail=y,f.ok=v,f.equal=function(e,t,n){e!=t&&y(e,t,n,"==",f.equal)},f.notEqual=function(e,t,n){e==t&&y(e,t,n,"!=",f.notEqual)},f.deepEqual=function(e,t,n){b(e,t,!1)||y(e,t,n,"deepEqual",f.deepEqual)},f.deepStrictEqual=function(e,t,n){b(e,t,!0)||y(e,t,n,"deepStrictEqual",f.deepStrictEqual)},f.notDeepEqual=function(e,t,n){b(e,t,!1)&&y(e,t,n,"notDeepEqual",f.notDeepEqual)},f.notDeepStrictEqual=function e(t,n,r){b(t,n,!0)&&y(t,n,r,"notDeepStrictEqual",e)},f.strictEqual=function(e,t,n){e!==t&&y(e,t,n,"===",f.strictEqual)},f.notStrictEqual=function(e,t,n){e===t&&y(e,t,n,"!==",f.notStrictEqual)},f.throws=function(e,t,n){E(!0,e,t,n)},f.doesNotThrow=function(e,t,n){E(!1,e,t,n)},f.ifError=function(e){if(e)throw e};var S=Object.keys||function(e){var t=[];for(var n in e)s.call(e,n)&&t.push(n);return t}}).call(this,n(10))},function(e,t){e.exports=function(e){return e&&"object"==typeof e&&"function"==typeof e.copy&&"function"==typeof e.fill&&"function"==typeof e.readUInt8}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){e.exports=n(11)},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t){},function(e,t,n){"use strict";var r=n(13).Buffer,o=n(60);e.exports=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length},e.prototype.unshift=function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length},e.prototype.shift=function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(e){if(0===this.length)return"";for(var t=this.head,n=""+t.data;t=t.next;)n+=e+t.data;return n},e.prototype.concat=function(e){if(0===this.length)return r.alloc(0);if(1===this.length)return this.head.data;for(var t,n,o,i=r.allocUnsafe(e>>>0),s=this.head,a=0;s;)t=s.data,n=i,o=a,t.copy(n,o),a+=s.data.length,s=s.next;return i},e}(),o&&o.inspect&&o.inspect.custom&&(e.exports.prototype[o.inspect.custom]=function(){var e=o.inspect({length:this.length});return this.constructor.name+" "+e})},function(e,t){},function(e,t,n){var r=n(5),o=r.Buffer;function i(e,t){for(var n in e)t[n]=e[n]}function s(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=s),i(o,s),s.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},s.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},s.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},s.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t,n){(function(e){var r=void 0!==e&&e||"undefined"!=typeof self&&self||window,o=Function.prototype.apply;function i(e,t){this._id=e,this._clearFn=t}t.setTimeout=function(){return new i(o.call(setTimeout,r,arguments),clearTimeout)},t.setInterval=function(){return new i(o.call(setInterval,r,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(r,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(63),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,n(10))},function(e,t,n){(function(e,t){!function(e,n){"use strict";if(!e.setImmediate){var r,o,i,s,a,c=1,u={},l=!1,f=e.document,h=Object.getPrototypeOf&&Object.getPrototypeOf(e);h=h&&h.setTimeout?h:e,"[object process]"==={}.toString.call(e.process)?r=function(e){t.nextTick(function(){d(e)})}:!function(){if(e.postMessage&&!e.importScripts){var t=!0,n=e.onmessage;return e.onmessage=function(){t=!1},e.postMessage("","*"),e.onmessage=n,t}}()?e.MessageChannel?((i=new MessageChannel).port1.onmessage=function(e){d(e.data)},r=function(e){i.port2.postMessage(e)}):f&&"onreadystatechange"in f.createElement("script")?(o=f.documentElement,r=function(e){var t=f.createElement("script");t.onreadystatechange=function(){d(e),t.onreadystatechange=null,o.removeChild(t),t=null},o.appendChild(t)}):r=function(e){setTimeout(d,0,e)}:(s="setImmediate$"+Math.random()+"$",a=function(t){t.source===e&&"string"==typeof t.data&&0===t.data.indexOf(s)&&d(+t.data.slice(s.length))},e.addEventListener?e.addEventListener("message",a,!1):e.attachEvent("onmessage",a),r=function(t){e.postMessage(s+t,"*")}),h.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n0?this._transform(null,t,n):n()},e.exports.decoder=c,e.exports.encoder=a},function(e,t,n){(t=e.exports=n(36)).Stream=t,t.Readable=t,t.Writable=n(41),t.Duplex=n(11),t.Transform=n(42),t.PassThrough=n(67)},function(e,t,n){"use strict";e.exports=i;var r=n(42),o=n(19);function i(e){if(!(this instanceof i))return new i(e);r.call(this,e)}o.inherits=n(14),o.inherits(i,r),i.prototype._transform=function(e,t,n){n(null,e)}},function(e,t,n){var r=n(22);function o(e){Error.call(this),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.message=e||"unable to decode"}n(35).inherits(o,Error),e.exports=function(e){return function(e){e instanceof r||(e=r().append(e));var t=i(e);if(t)return e.consume(t.bytesConsumed),t.value;throw new o};function t(e,t,n){return t>=n+e}function n(e,t){return{value:e,bytesConsumed:t}}function i(e,r){r=void 0===r?0:r;var o=e.length-r;if(o<=0)return null;var i,l,f,h=e.readUInt8(r),p=0;if(!function(e,t){var n=function(e){switch(e){case 196:return 2;case 197:return 3;case 198:return 5;case 199:return 3;case 200:return 4;case 201:return 6;case 202:return 5;case 203:return 9;case 204:return 2;case 205:return 3;case 206:return 5;case 207:return 9;case 208:return 2;case 209:return 3;case 210:return 5;case 211:return 9;case 212:return 3;case 213:return 4;case 214:return 6;case 215:return 10;case 216:return 18;case 217:return 2;case 218:return 3;case 219:return 5;case 222:return 3;default:return-1}}(e);return!(-1!==n&&t=0;f--)p+=e.readUInt8(r+f+1)*Math.pow(2,8*(7-f));return n(p,9);case 208:return n(p=e.readInt8(r+1),2);case 209:return n(p=e.readInt16BE(r+1),3);case 210:return n(p=e.readInt32BE(r+1),5);case 211:return n(p=function(e,t){var n=128==(128&e[t]);if(n)for(var r=1,o=t+7;o>=t;o--){var i=(255^e[o])+r;e[o]=255&i,r=i>>8}var s=e.readUInt32BE(t+0),a=e.readUInt32BE(t+4);return(4294967296*s+a)*(n?-1:1)}(e.slice(r+1,r+9),0),9);case 202:return n(p=e.readFloatBE(r+1),5);case 203:return n(p=e.readDoubleBE(r+1),9);case 217:return t(i=e.readUInt8(r+1),o,2)?n(p=e.toString("utf8",r+2,r+2+i),2+i):null;case 218:return t(i=e.readUInt16BE(r+1),o,3)?n(p=e.toString("utf8",r+3,r+3+i),3+i):null;case 219:return t(i=e.readUInt32BE(r+1),o,5)?n(p=e.toString("utf8",r+5,r+5+i),5+i):null;case 196:return t(i=e.readUInt8(r+1),o,2)?n(p=e.slice(r+2,r+2+i),2+i):null;case 197:return t(i=e.readUInt16BE(r+1),o,3)?n(p=e.slice(r+3,r+3+i),3+i):null;case 198:return t(i=e.readUInt32BE(r+1),o,5)?n(p=e.slice(r+5,r+5+i),5+i):null;case 220:return o<3?null:(i=e.readUInt16BE(r+1),s(e,r,i,3));case 221:return o<5?null:(i=e.readUInt32BE(r+1),s(e,r,i,5));case 222:return i=e.readUInt16BE(r+1),a(e,r,i,3);case 223:throw new Error("map too big to decode in JS");case 212:return c(e,r,1);case 213:return c(e,r,2);case 214:return c(e,r,4);case 215:return c(e,r,8);case 216:return c(e,r,16);case 199:return i=e.readUInt8(r+1),l=e.readUInt8(r+2),t(i,o,3)?u(e,r,l,i,3):null;case 200:return i=e.readUInt16BE(r+1),l=e.readUInt8(r+3),t(i,o,4)?u(e,r,l,i,4):null;case 201:return i=e.readUInt32BE(r+1),l=e.readUInt8(r+5),t(i,o,6)?u(e,r,l,i,6):null}if(144==(240&h))return s(e,r,i=15&h,1);if(128==(240&h))return a(e,r,i=15&h,1);if(160==(224&h))return t(i=31&h,o,1)?n(p=e.toString("utf8",r+1,r+i+1),i+1):null;if(h>=224)return n(p=h-256,1);if(h<128)return n(h,1);throw new Error("not implemented yet")}function s(e,t,r,o){var s,a=[],c=0;for(t+=o,s=0;si)&&((n=r.allocUnsafe(9))[0]=203,n.writeDoubleBE(e,1)),n}e.exports=function(e,t,n,i){function a(c,u){var l,f,h;if(void 0===c)throw new Error("undefined is not encodable in msgpack!");if(null===c)(l=r.allocUnsafe(1))[0]=192;else if(!0===c)(l=r.allocUnsafe(1))[0]=195;else if(!1===c)(l=r.allocUnsafe(1))[0]=194;else if("string"==typeof c)(f=r.byteLength(c))<32?((l=r.allocUnsafe(1+f))[0]=160|f,f>0&&l.write(c,1)):f<=255&&!n?((l=r.allocUnsafe(2+f))[0]=217,l[1]=f,l.write(c,2)):f<=65535?((l=r.allocUnsafe(3+f))[0]=218,l.writeUInt16BE(f,1),l.write(c,3)):((l=r.allocUnsafe(5+f))[0]=219,l.writeUInt32BE(f,1),l.write(c,5));else if(c&&(c.readUInt32LE||c instanceof Uint8Array))c instanceof Uint8Array&&(c=r.from(c)),c.length<=255?((l=r.allocUnsafe(2))[0]=196,l[1]=c.length):c.length<=65535?((l=r.allocUnsafe(3))[0]=197,l.writeUInt16BE(c.length,1)):((l=r.allocUnsafe(5))[0]=198,l.writeUInt32BE(c.length,1)),l=o([l,c]);else if(Array.isArray(c))c.length<16?(l=r.allocUnsafe(1))[0]=144|c.length:c.length<65536?((l=r.allocUnsafe(3))[0]=220,l.writeUInt16BE(c.length,1)):((l=r.allocUnsafe(5))[0]=221,l.writeUInt32BE(c.length,1)),l=c.reduce(function(e,t){return e.append(a(t,!0)),e},o().append(l));else{if(!i&&"function"==typeof c.getDate)return function(e){var t,n=1*e,i=Math.floor(n/1e3),s=1e6*(n-1e3*i);if(s||i>4294967295){(t=new r(10))[0]=215,t[1]=-1;var a=4*s,c=i/Math.pow(2,32),u=a+c&4294967295,l=4294967295&i;t.writeInt32BE(u,2),t.writeInt32BE(l,6)}else(t=new r(6))[0]=214,t[1]=-1,t.writeUInt32BE(Math.floor(n/1e3),2);return o().append(t)}(c);if("object"==typeof c)l=function(t){var n,i,s=-1,a=[];for(n=0;n>8),a.push(255&s)):(a.push(201),a.push(s>>24),a.push(s>>16&255),a.push(s>>8&255),a.push(255&s));return o().append(r.from(a)).append(i)}(c)||function(e){var t,n,i=[],s=0;for(t in e)e.hasOwnProperty(t)&&void 0!==e[t]&&"function"!=typeof e[t]&&(++s,i.push(a(t,!0)),i.push(a(e[t],!0)));s<16?(n=r.allocUnsafe(1))[0]=128|s:((n=r.allocUnsafe(3))[0]=222,n.writeUInt16BE(s,1));return i.unshift(n),i.reduce(function(e,t){return e.append(t)},o())}(c);else if("number"==typeof c){if((h=c)!==Math.floor(h))return s(c,t);if(c>=0)if(c<128)(l=r.allocUnsafe(1))[0]=c;else if(c<256)(l=r.allocUnsafe(2))[0]=204,l[1]=c;else if(c<65536)(l=r.allocUnsafe(3))[0]=205,l.writeUInt16BE(c,1);else if(c<=4294967295)(l=r.allocUnsafe(5))[0]=206,l.writeUInt32BE(c,1);else{if(!(c<=9007199254740991))return s(c,!0);(l=r.allocUnsafe(9))[0]=207,function(e,t){for(var n=7;n>=0;n--)e[n+1]=255&t,t/=256}(l,c)}else if(c>=-32)(l=r.allocUnsafe(1))[0]=256+c;else if(c>=-128)(l=r.allocUnsafe(2))[0]=208,l.writeInt8(c,1);else if(c>=-32768)(l=r.allocUnsafe(3))[0]=209,l.writeInt16BE(c,1);else if(c>-214748365)(l=r.allocUnsafe(5))[0]=210,l.writeInt32BE(c,1);else{if(!(c>=-9007199254740991))return s(c,!0);(l=r.allocUnsafe(9))[0]=211,function(e,t,n){var r=n<0;r&&(n=Math.abs(n));var o=n%4294967296,i=n/4294967296;if(e.writeUInt32BE(Math.floor(i),t+0),e.writeUInt32BE(o,t+4),r)for(var s=1,a=t+7;a>=t;a--){var c=(255^e[a])+s;e[a]=255&c,s=c>>8}}(l,1,c)}}}if(!l)throw new Error("not implemented yet");return u?l:l.slice()}return a}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(e){i(e)}}function a(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(s,a)}c((r=r.apply(e,t||[])).next())})},o=this&&this.__generator||function(e,t){var n,r,o,i,s={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(i){return function(a){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;s;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return s.label++,{value:i[1],done:!1};case 5:s.label++,r=i[1],i=[0];continue;case 7:i=s.ops.pop(),s.trys.pop();continue;default:if(!(o=(o=s.trys).length>0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]this.nextBatchId?this.fatalError?(this.logger.log(a.LogLevel.Debug,"Received a new batch "+e+" but errored out on a previous batch "+(this.nextBatchId-1)),[4,n.send("OnRenderCompleted",this.nextBatchId-1,this.fatalError.toString())]):[3,4]:[3,5];case 3:return o.sent(),[2];case 4:return this.logger.log(a.LogLevel.Debug,"Waiting for batch "+this.nextBatchId+". Batch "+e+" not processed."),[2];case 5:return o.trys.push([5,7,,8]),this.nextBatchId++,this.logger.log(a.LogLevel.Debug,"Applying batch "+e+"."),i.renderBatch(this.browserRendererId,new s.OutOfProcessRenderBatch(t)),[4,this.completeBatch(n,e)];case 6:return o.sent(),[3,8];case 7:throw r=o.sent(),this.fatalError=r.toString(),this.logger.log(a.LogLevel.Error,"There was an error applying batch "+e+"."),n.send("OnRenderCompleted",e,r.toString()),r;case 8:return[2]}})})},e.prototype.getLastBatchid=function(){return this.nextBatchId-1},e.prototype.completeBatch=function(e,t){return r(this,void 0,void 0,function(){return o(this,function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),[4,e.send("OnRenderCompleted",t,null)];case 1:return n.sent(),[3,3];case 2:return n.sent(),this.logger.log(a.LogLevel.Warning,"Failed to deliver completion notification for render '"+t+"'."),[3,3];case 3:return[2]}})})},e.renderQueues=new Map,e}();t.RenderQueue=c},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(72),o=Math.pow(2,32),i=Math.pow(2,21)-1,s=function(){function e(e){this.batchData=e;var t=new l(e);this.arrayRangeReader=new f(e),this.arrayBuilderSegmentReader=new h(e),this.diffReader=new a(e),this.editReader=new c(e,t),this.frameReader=new u(e,t)}return e.prototype.updatedComponents=function(){return p(this.batchData,this.batchData.length-20)},e.prototype.referenceFrames=function(){return p(this.batchData,this.batchData.length-16)},e.prototype.disposedComponentIds=function(){return p(this.batchData,this.batchData.length-12)},e.prototype.disposedEventHandlerIds=function(){return p(this.batchData,this.batchData.length-8)},e.prototype.updatedComponentsEntry=function(e,t){var n=e+4*t;return p(this.batchData,n)},e.prototype.referenceFramesEntry=function(e,t){return e+20*t},e.prototype.disposedComponentIdsEntry=function(e,t){var n=e+4*t;return p(this.batchData,n)},e.prototype.disposedEventHandlerIdsEntry=function(e,t){var n=e+8*t;return g(this.batchData,n)},e}();t.OutOfProcessRenderBatch=s;var a=function(){function e(e){this.batchDataUint8=e}return e.prototype.componentId=function(e){return p(this.batchDataUint8,e)},e.prototype.edits=function(e){return e+4},e.prototype.editsEntry=function(e,t){return e+16*t},e}(),c=function(){function e(e,t){this.batchDataUint8=e,this.stringReader=t}return e.prototype.editType=function(e){return p(this.batchDataUint8,e)},e.prototype.siblingIndex=function(e){return p(this.batchDataUint8,e+4)},e.prototype.newTreeIndex=function(e){return p(this.batchDataUint8,e+8)},e.prototype.moveToSiblingIndex=function(e){return p(this.batchDataUint8,e+8)},e.prototype.removedAttributeName=function(e){var t=p(this.batchDataUint8,e+12);return this.stringReader.readString(t)},e}(),u=function(){function e(e,t){this.batchDataUint8=e,this.stringReader=t}return e.prototype.frameType=function(e){return p(this.batchDataUint8,e)},e.prototype.subtreeLength=function(e){return p(this.batchDataUint8,e+4)},e.prototype.elementReferenceCaptureId=function(e){var t=p(this.batchDataUint8,e+4);return this.stringReader.readString(t)},e.prototype.componentId=function(e){return p(this.batchDataUint8,e+8)},e.prototype.elementName=function(e){var t=p(this.batchDataUint8,e+8);return this.stringReader.readString(t)},e.prototype.textContent=function(e){var t=p(this.batchDataUint8,e+4);return this.stringReader.readString(t)},e.prototype.markupContent=function(e){var t=p(this.batchDataUint8,e+4);return this.stringReader.readString(t)},e.prototype.attributeName=function(e){var t=p(this.batchDataUint8,e+4);return this.stringReader.readString(t)},e.prototype.attributeValue=function(e){var t=p(this.batchDataUint8,e+8);return this.stringReader.readString(t)},e.prototype.attributeEventHandlerId=function(e){return g(this.batchDataUint8,e+12)},e}(),l=function(){function e(e){this.batchDataUint8=e,this.stringTableStartIndex=p(e,e.length-4)}return e.prototype.readString=function(e){if(-1===e)return null;var t,n=p(this.batchDataUint8,this.stringTableStartIndex+4*e),o=function(e,t){for(var n=0,r=0,o=0;o<4;o++){var i=e[t+o];if(n|=(127&i)<>>0)}function g(e,t){var n=d(e,t+4);if(n>i)throw new Error("Cannot read uint64 with high order part "+n+", because the result would exceed Number.MAX_SAFE_INTEGER.");return n*o+d(e,t)}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r="function"==typeof TextDecoder?new TextDecoder("utf-8"):null;t.decodeUtf8=r?r.decode.bind(r):function(e){var t=0,n=e.length,r=[],o=[];for(;t65535&&(u-=65536,r.push(u>>>10&1023|55296),u=56320|1023&u),r.push(u)}r.length>1024&&(o.push(String.fromCharCode.apply(null,r)),r.length=0)}return o.push(String.fromCharCode.apply(null,r)),o.join("")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(20),o=function(){function e(){}return e.prototype.log=function(e,t){},e.instance=new e,e}();t.NullLogger=o;var i=function(){function e(e){this.minimumLogLevel=e}return e.prototype.log=function(e,t){if(e>=this.minimumLogLevel)switch(e){case r.LogLevel.Critical:case r.LogLevel.Error:console.error("["+(new Date).toISOString()+"] "+r.LogLevel[e]+": "+t);break;case r.LogLevel.Warning:console.warn("["+(new Date).toISOString()+"] "+r.LogLevel[e]+": "+t);break;case r.LogLevel.Information:console.info("["+(new Date).toISOString()+"] "+r.LogLevel[e]+": "+t);break;default:console.log("["+(new Date).toISOString()+"] "+r.LogLevel[e]+": "+t)}},e}();t.ConsoleLogger=i},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,i){function s(e){try{c(r.next(e))}catch(e){i(e)}}function a(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(s,a)}c((r=r.apply(e,t||[])).next())})},o=this&&this.__generator||function(e,t){var n,r,o,i,s={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(i){return function(a){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;s;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return s.label++,{value:i[1],done:!1};case 5:s.label++,r=i[1],i=[0];continue;case 7:i=s.ops.pop(),s.trys.pop();continue;default:if(!(o=(o=s.trys).length>0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]>=7)>0&&(r|=128),n.push(r)}while(t>0);t=e.byteLength||e.length;var o=new Uint8Array(n.length+t);return o.set(n,0),o.set(e,n.length),o.buffer},e.parse=function(e){for(var t=[],n=new Uint8Array(e),r=[0,7,14,21,28],o=0;o7)throw new Error("Messages bigger than 2GB are not supported.");if(!(n.byteLength>=o+i+s))throw new Error("Incomplete message.");t.push(n.slice?n.slice(o+i,o+i+s):n.subarray(o+i,o+i+s)),o=o+i+s}return t},e}();var a=new Uint8Array([145,i.MessageType.Ping]),c=function(){function e(){this.name="messagepack",this.version=1,this.transferFormat=i.TransferFormat.Binary,this.errorResult=1,this.voidResult=2,this.nonVoidResult=3}return e.prototype.parseMessages=function(e,t){if(!(e instanceof r.Buffer||(n=e,n&&"undefined"!=typeof ArrayBuffer&&(n instanceof ArrayBuffer||n.constructor&&"ArrayBuffer"===n.constructor.name))))throw new Error("Invalid input for MessagePack hub protocol. Expected an ArrayBuffer or Buffer.");var n;null===t&&(t=i.NullLogger.instance);for(var o=[],a=0,c=s.parse(e);a=0;u--)if(l[u]!==f[u])return!1;for(u=l.length-1;u>=0;u--)if(c=l[u],!b(e[c],t[c],n,r))return!1;return!0}(e,t,n,a))}return n?e===t:e==t}function m(e){return"[object Arguments]"==Object.prototype.toString.call(e)}function w(e,t){if(!e||!t)return!1;if("[object RegExp]"==Object.prototype.toString.call(t))return t.test(e);try{if(e instanceof t)return!0}catch(e){}return!Error.isPrototypeOf(t)&&!0===t.call({},e)}function E(e,t,n,r){var o;if("function"!=typeof t)throw new TypeError('"block" argument must be a function');"string"==typeof n&&(r=n,n=null),o=function(e){var t;try{e()}catch(e){t=e}return t}(t),r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),e&&!o&&y(o,n,"Missing expected exception"+r);var a="string"==typeof r,s=!e&&o&&!n;if((!e&&i.isError(o)&&a&&w(o,n)||s)&&y(o,n,"Got unwanted exception"+r),e&&o&&n&&!w(o,n)||!e&&o)throw o}f.AssertionError=function(e){var t;this.name="AssertionError",this.actual=e.actual,this.expected=e.expected,this.operator=e.operator,e.message?(this.message=e.message,this.generatedMessage=!1):(this.message=d(g((t=this).actual),128)+" "+t.operator+" "+d(g(t.expected),128),this.generatedMessage=!0);var n=e.stackStartFunction||y;if(Error.captureStackTrace)Error.captureStackTrace(this,n);else{var r=new Error;if(r.stack){var o=r.stack,i=p(n),a=o.indexOf("\n"+i);if(a>=0){var s=o.indexOf("\n",a+1);o=o.substring(s+1)}this.stack=o}}},i.inherits(f.AssertionError,Error),f.fail=y,f.ok=v,f.equal=function(e,t,n){e!=t&&y(e,t,n,"==",f.equal)},f.notEqual=function(e,t,n){e==t&&y(e,t,n,"!=",f.notEqual)},f.deepEqual=function(e,t,n){b(e,t,!1)||y(e,t,n,"deepEqual",f.deepEqual)},f.deepStrictEqual=function(e,t,n){b(e,t,!0)||y(e,t,n,"deepStrictEqual",f.deepStrictEqual)},f.notDeepEqual=function(e,t,n){b(e,t,!1)&&y(e,t,n,"notDeepEqual",f.notDeepEqual)},f.notDeepStrictEqual=function e(t,n,r){b(t,n,!0)&&y(t,n,r,"notDeepStrictEqual",e)},f.strictEqual=function(e,t,n){e!==t&&y(e,t,n,"===",f.strictEqual)},f.notStrictEqual=function(e,t,n){e===t&&y(e,t,n,"!==",f.notStrictEqual)},f.throws=function(e,t,n){E(!0,e,t,n)},f.doesNotThrow=function(e,t,n){E(!1,e,t,n)},f.ifError=function(e){if(e)throw e};var S=Object.keys||function(e){var t=[];for(var n in e)a.call(e,n)&&t.push(n);return t}}).call(this,n(10))},function(e,t){e.exports=function(e){return e&&"object"==typeof e&&"function"==typeof e.copy&&"function"==typeof e.fill&&"function"==typeof e.readUInt8}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){e.exports=n(11)},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t){},function(e,t,n){"use strict";var r=n(13).Buffer,o=n(60);e.exports=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length},e.prototype.unshift=function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length},e.prototype.shift=function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(e){if(0===this.length)return"";for(var t=this.head,n=""+t.data;t=t.next;)n+=e+t.data;return n},e.prototype.concat=function(e){if(0===this.length)return r.alloc(0);if(1===this.length)return this.head.data;for(var t,n,o,i=r.allocUnsafe(e>>>0),a=this.head,s=0;a;)t=a.data,n=i,o=s,t.copy(n,o),s+=a.data.length,a=a.next;return i},e}(),o&&o.inspect&&o.inspect.custom&&(e.exports.prototype[o.inspect.custom]=function(){var e=o.inspect({length:this.length});return this.constructor.name+" "+e})},function(e,t){},function(e,t,n){var r=n(5),o=r.Buffer;function i(e,t){for(var n in e)t[n]=e[n]}function a(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=a),i(o,a),a.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},a.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},a.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},a.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t,n){(function(e){var r=void 0!==e&&e||"undefined"!=typeof self&&self||window,o=Function.prototype.apply;function i(e,t){this._id=e,this._clearFn=t}t.setTimeout=function(){return new i(o.call(setTimeout,r,arguments),clearTimeout)},t.setInterval=function(){return new i(o.call(setInterval,r,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(r,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(63),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,n(10))},function(e,t,n){(function(e,t){!function(e,n){"use strict";if(!e.setImmediate){var r,o,i,a,s,c=1,u={},l=!1,f=e.document,h=Object.getPrototypeOf&&Object.getPrototypeOf(e);h=h&&h.setTimeout?h:e,"[object process]"==={}.toString.call(e.process)?r=function(e){t.nextTick(function(){d(e)})}:!function(){if(e.postMessage&&!e.importScripts){var t=!0,n=e.onmessage;return e.onmessage=function(){t=!1},e.postMessage("","*"),e.onmessage=n,t}}()?e.MessageChannel?((i=new MessageChannel).port1.onmessage=function(e){d(e.data)},r=function(e){i.port2.postMessage(e)}):f&&"onreadystatechange"in f.createElement("script")?(o=f.documentElement,r=function(e){var t=f.createElement("script");t.onreadystatechange=function(){d(e),t.onreadystatechange=null,o.removeChild(t),t=null},o.appendChild(t)}):r=function(e){setTimeout(d,0,e)}:(a="setImmediate$"+Math.random()+"$",s=function(t){t.source===e&&"string"==typeof t.data&&0===t.data.indexOf(a)&&d(+t.data.slice(a.length))},e.addEventListener?e.addEventListener("message",s,!1):e.attachEvent("onmessage",s),r=function(t){e.postMessage(a+t,"*")}),h.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n0?this._transform(null,t,n):n()},e.exports.decoder=c,e.exports.encoder=s},function(e,t,n){(t=e.exports=n(36)).Stream=t,t.Readable=t,t.Writable=n(41),t.Duplex=n(11),t.Transform=n(42),t.PassThrough=n(67)},function(e,t,n){"use strict";e.exports=i;var r=n(42),o=n(19);function i(e){if(!(this instanceof i))return new i(e);r.call(this,e)}o.inherits=n(14),o.inherits(i,r),i.prototype._transform=function(e,t,n){n(null,e)}},function(e,t,n){var r=n(22);function o(e){Error.call(this),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.message=e||"unable to decode"}n(35).inherits(o,Error),e.exports=function(e){return function(e){e instanceof r||(e=r().append(e));var t=i(e);if(t)return e.consume(t.bytesConsumed),t.value;throw new o};function t(e,t,n){return t>=n+e}function n(e,t){return{value:e,bytesConsumed:t}}function i(e,r){r=void 0===r?0:r;var o=e.length-r;if(o<=0)return null;var i,l,f,h=e.readUInt8(r),p=0;if(!function(e,t){var n=function(e){switch(e){case 196:return 2;case 197:return 3;case 198:return 5;case 199:return 3;case 200:return 4;case 201:return 6;case 202:return 5;case 203:return 9;case 204:return 2;case 205:return 3;case 206:return 5;case 207:return 9;case 208:return 2;case 209:return 3;case 210:return 5;case 211:return 9;case 212:return 3;case 213:return 4;case 214:return 6;case 215:return 10;case 216:return 18;case 217:return 2;case 218:return 3;case 219:return 5;case 222:return 3;default:return-1}}(e);return!(-1!==n&&t=0;f--)p+=e.readUInt8(r+f+1)*Math.pow(2,8*(7-f));return n(p,9);case 208:return n(p=e.readInt8(r+1),2);case 209:return n(p=e.readInt16BE(r+1),3);case 210:return n(p=e.readInt32BE(r+1),5);case 211:return n(p=function(e,t){var n=128==(128&e[t]);if(n)for(var r=1,o=t+7;o>=t;o--){var i=(255^e[o])+r;e[o]=255&i,r=i>>8}var a=e.readUInt32BE(t+0),s=e.readUInt32BE(t+4);return(4294967296*a+s)*(n?-1:1)}(e.slice(r+1,r+9),0),9);case 202:return n(p=e.readFloatBE(r+1),5);case 203:return n(p=e.readDoubleBE(r+1),9);case 217:return t(i=e.readUInt8(r+1),o,2)?n(p=e.toString("utf8",r+2,r+2+i),2+i):null;case 218:return t(i=e.readUInt16BE(r+1),o,3)?n(p=e.toString("utf8",r+3,r+3+i),3+i):null;case 219:return t(i=e.readUInt32BE(r+1),o,5)?n(p=e.toString("utf8",r+5,r+5+i),5+i):null;case 196:return t(i=e.readUInt8(r+1),o,2)?n(p=e.slice(r+2,r+2+i),2+i):null;case 197:return t(i=e.readUInt16BE(r+1),o,3)?n(p=e.slice(r+3,r+3+i),3+i):null;case 198:return t(i=e.readUInt32BE(r+1),o,5)?n(p=e.slice(r+5,r+5+i),5+i):null;case 220:return o<3?null:(i=e.readUInt16BE(r+1),a(e,r,i,3));case 221:return o<5?null:(i=e.readUInt32BE(r+1),a(e,r,i,5));case 222:return i=e.readUInt16BE(r+1),s(e,r,i,3);case 223:throw new Error("map too big to decode in JS");case 212:return c(e,r,1);case 213:return c(e,r,2);case 214:return c(e,r,4);case 215:return c(e,r,8);case 216:return c(e,r,16);case 199:return i=e.readUInt8(r+1),l=e.readUInt8(r+2),t(i,o,3)?u(e,r,l,i,3):null;case 200:return i=e.readUInt16BE(r+1),l=e.readUInt8(r+3),t(i,o,4)?u(e,r,l,i,4):null;case 201:return i=e.readUInt32BE(r+1),l=e.readUInt8(r+5),t(i,o,6)?u(e,r,l,i,6):null}if(144==(240&h))return a(e,r,i=15&h,1);if(128==(240&h))return s(e,r,i=15&h,1);if(160==(224&h))return t(i=31&h,o,1)?n(p=e.toString("utf8",r+1,r+i+1),i+1):null;if(h>=224)return n(p=h-256,1);if(h<128)return n(h,1);throw new Error("not implemented yet")}function a(e,t,r,o){var a,s=[],c=0;for(t+=o,a=0;ai)&&((n=r.allocUnsafe(9))[0]=203,n.writeDoubleBE(e,1)),n}e.exports=function(e,t,n,i){function s(c,u){var l,f,h;if(void 0===c)throw new Error("undefined is not encodable in msgpack!");if(null===c)(l=r.allocUnsafe(1))[0]=192;else if(!0===c)(l=r.allocUnsafe(1))[0]=195;else if(!1===c)(l=r.allocUnsafe(1))[0]=194;else if("string"==typeof c)(f=r.byteLength(c))<32?((l=r.allocUnsafe(1+f))[0]=160|f,f>0&&l.write(c,1)):f<=255&&!n?((l=r.allocUnsafe(2+f))[0]=217,l[1]=f,l.write(c,2)):f<=65535?((l=r.allocUnsafe(3+f))[0]=218,l.writeUInt16BE(f,1),l.write(c,3)):((l=r.allocUnsafe(5+f))[0]=219,l.writeUInt32BE(f,1),l.write(c,5));else if(c&&(c.readUInt32LE||c instanceof Uint8Array))c instanceof Uint8Array&&(c=r.from(c)),c.length<=255?((l=r.allocUnsafe(2))[0]=196,l[1]=c.length):c.length<=65535?((l=r.allocUnsafe(3))[0]=197,l.writeUInt16BE(c.length,1)):((l=r.allocUnsafe(5))[0]=198,l.writeUInt32BE(c.length,1)),l=o([l,c]);else if(Array.isArray(c))c.length<16?(l=r.allocUnsafe(1))[0]=144|c.length:c.length<65536?((l=r.allocUnsafe(3))[0]=220,l.writeUInt16BE(c.length,1)):((l=r.allocUnsafe(5))[0]=221,l.writeUInt32BE(c.length,1)),l=c.reduce(function(e,t){return e.append(s(t,!0)),e},o().append(l));else{if(!i&&"function"==typeof c.getDate)return function(e){var t,n=1*e,i=Math.floor(n/1e3),a=1e6*(n-1e3*i);if(a||i>4294967295){(t=new r(10))[0]=215,t[1]=-1;var s=4*a,c=i/Math.pow(2,32),u=s+c&4294967295,l=4294967295&i;t.writeInt32BE(u,2),t.writeInt32BE(l,6)}else(t=new r(6))[0]=214,t[1]=-1,t.writeUInt32BE(Math.floor(n/1e3),2);return o().append(t)}(c);if("object"==typeof c)l=function(t){var n,i,a=-1,s=[];for(n=0;n>8),s.push(255&a)):(s.push(201),s.push(a>>24),s.push(a>>16&255),s.push(a>>8&255),s.push(255&a));return o().append(r.from(s)).append(i)}(c)||function(e){var t,n,i=[],a=0;for(t in e)e.hasOwnProperty(t)&&void 0!==e[t]&&"function"!=typeof e[t]&&(++a,i.push(s(t,!0)),i.push(s(e[t],!0)));a<16?(n=r.allocUnsafe(1))[0]=128|a:((n=r.allocUnsafe(3))[0]=222,n.writeUInt16BE(a,1));return i.unshift(n),i.reduce(function(e,t){return e.append(t)},o())}(c);else if("number"==typeof c){if((h=c)!==Math.floor(h))return a(c,t);if(c>=0)if(c<128)(l=r.allocUnsafe(1))[0]=c;else if(c<256)(l=r.allocUnsafe(2))[0]=204,l[1]=c;else if(c<65536)(l=r.allocUnsafe(3))[0]=205,l.writeUInt16BE(c,1);else if(c<=4294967295)(l=r.allocUnsafe(5))[0]=206,l.writeUInt32BE(c,1);else{if(!(c<=9007199254740991))return a(c,!0);(l=r.allocUnsafe(9))[0]=207,function(e,t){for(var n=7;n>=0;n--)e[n+1]=255&t,t/=256}(l,c)}else if(c>=-32)(l=r.allocUnsafe(1))[0]=256+c;else if(c>=-128)(l=r.allocUnsafe(2))[0]=208,l.writeInt8(c,1);else if(c>=-32768)(l=r.allocUnsafe(3))[0]=209,l.writeInt16BE(c,1);else if(c>-214748365)(l=r.allocUnsafe(5))[0]=210,l.writeInt32BE(c,1);else{if(!(c>=-9007199254740991))return a(c,!0);(l=r.allocUnsafe(9))[0]=211,function(e,t,n){var r=n<0;r&&(n=Math.abs(n));var o=n%4294967296,i=n/4294967296;if(e.writeUInt32BE(Math.floor(i),t+0),e.writeUInt32BE(o,t+4),r)for(var a=1,s=t+7;s>=t;s--){var c=(255^e[s])+a;e[s]=255&c,a=c>>8}}(l,1,c)}}}if(!l)throw new Error("not implemented yet");return u?l:l.slice()}return s}},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,i){function a(e){try{c(r.next(e))}catch(e){i(e)}}function s(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(a,s)}c((r=r.apply(e,t||[])).next())})},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=(o=a.trys).length>0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]this.nextBatchId?this.fatalError?(this.logger.log(s.LogLevel.Debug,"Received a new batch "+e+" but errored out on a previous batch "+(this.nextBatchId-1)),[4,n.send("OnRenderCompleted",this.nextBatchId-1,this.fatalError.toString())]):[3,4]:[3,5];case 3:return o.sent(),[2];case 4:return this.logger.log(s.LogLevel.Debug,"Waiting for batch "+this.nextBatchId+". Batch "+e+" not processed."),[2];case 5:return o.trys.push([5,7,,8]),this.nextBatchId++,this.logger.log(s.LogLevel.Debug,"Applying batch "+e+"."),i.renderBatch(this.browserRendererId,new a.OutOfProcessRenderBatch(t)),[4,this.completeBatch(n,e)];case 6:return o.sent(),[3,8];case 7:throw r=o.sent(),this.fatalError=r.toString(),this.logger.log(s.LogLevel.Error,"There was an error applying batch "+e+"."),n.send("OnRenderCompleted",e,r.toString()),r;case 8:return[2]}})})},e.prototype.getLastBatchid=function(){return this.nextBatchId-1},e.prototype.completeBatch=function(e,t){return r(this,void 0,void 0,function(){return o(this,function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),[4,e.send("OnRenderCompleted",t,null)];case 1:return n.sent(),[3,3];case 2:return n.sent(),this.logger.log(s.LogLevel.Warning,"Failed to deliver completion notification for render '"+t+"'."),[3,3];case 3:return[2]}})})},e}();t.RenderQueue=c},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(72),o=Math.pow(2,32),i=Math.pow(2,21)-1,a=function(){function e(e){this.batchData=e;var t=new l(e);this.arrayRangeReader=new f(e),this.arrayBuilderSegmentReader=new h(e),this.diffReader=new s(e),this.editReader=new c(e,t),this.frameReader=new u(e,t)}return e.prototype.updatedComponents=function(){return p(this.batchData,this.batchData.length-20)},e.prototype.referenceFrames=function(){return p(this.batchData,this.batchData.length-16)},e.prototype.disposedComponentIds=function(){return p(this.batchData,this.batchData.length-12)},e.prototype.disposedEventHandlerIds=function(){return p(this.batchData,this.batchData.length-8)},e.prototype.updatedComponentsEntry=function(e,t){var n=e+4*t;return p(this.batchData,n)},e.prototype.referenceFramesEntry=function(e,t){return e+20*t},e.prototype.disposedComponentIdsEntry=function(e,t){var n=e+4*t;return p(this.batchData,n)},e.prototype.disposedEventHandlerIdsEntry=function(e,t){var n=e+8*t;return g(this.batchData,n)},e}();t.OutOfProcessRenderBatch=a;var s=function(){function e(e){this.batchDataUint8=e}return e.prototype.componentId=function(e){return p(this.batchDataUint8,e)},e.prototype.edits=function(e){return e+4},e.prototype.editsEntry=function(e,t){return e+16*t},e}(),c=function(){function e(e,t){this.batchDataUint8=e,this.stringReader=t}return e.prototype.editType=function(e){return p(this.batchDataUint8,e)},e.prototype.siblingIndex=function(e){return p(this.batchDataUint8,e+4)},e.prototype.newTreeIndex=function(e){return p(this.batchDataUint8,e+8)},e.prototype.moveToSiblingIndex=function(e){return p(this.batchDataUint8,e+8)},e.prototype.removedAttributeName=function(e){var t=p(this.batchDataUint8,e+12);return this.stringReader.readString(t)},e}(),u=function(){function e(e,t){this.batchDataUint8=e,this.stringReader=t}return e.prototype.frameType=function(e){return p(this.batchDataUint8,e)},e.prototype.subtreeLength=function(e){return p(this.batchDataUint8,e+4)},e.prototype.elementReferenceCaptureId=function(e){var t=p(this.batchDataUint8,e+4);return this.stringReader.readString(t)},e.prototype.componentId=function(e){return p(this.batchDataUint8,e+8)},e.prototype.elementName=function(e){var t=p(this.batchDataUint8,e+8);return this.stringReader.readString(t)},e.prototype.textContent=function(e){var t=p(this.batchDataUint8,e+4);return this.stringReader.readString(t)},e.prototype.markupContent=function(e){var t=p(this.batchDataUint8,e+4);return this.stringReader.readString(t)},e.prototype.attributeName=function(e){var t=p(this.batchDataUint8,e+4);return this.stringReader.readString(t)},e.prototype.attributeValue=function(e){var t=p(this.batchDataUint8,e+8);return this.stringReader.readString(t)},e.prototype.attributeEventHandlerId=function(e){return g(this.batchDataUint8,e+12)},e}(),l=function(){function e(e){this.batchDataUint8=e,this.stringTableStartIndex=p(e,e.length-4)}return e.prototype.readString=function(e){if(-1===e)return null;var t,n=p(this.batchDataUint8,this.stringTableStartIndex+4*e),o=function(e,t){for(var n=0,r=0,o=0;o<4;o++){var i=e[t+o];if(n|=(127&i)<>>0)}function g(e,t){var n=d(e,t+4);if(n>i)throw new Error("Cannot read uint64 with high order part "+n+", because the result would exceed Number.MAX_SAFE_INTEGER.");return n*o+d(e,t)}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r="function"==typeof TextDecoder?new TextDecoder("utf-8"):null;t.decodeUtf8=r?r.decode.bind(r):function(e){var t=0,n=e.length,r=[],o=[];for(;t65535&&(u-=65536,r.push(u>>>10&1023|55296),u=56320|1023&u),r.push(u)}r.length>1024&&(o.push(String.fromCharCode.apply(null,r)),r.length=0)}return o.push(String.fromCharCode.apply(null,r)),o.join("")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(20),o=function(){function e(){}return e.prototype.log=function(e,t){},e.instance=new e,e}();t.NullLogger=o;var i=function(){function e(e){this.minimumLogLevel=e}return e.prototype.log=function(e,t){if(e>=this.minimumLogLevel)switch(e){case r.LogLevel.Critical:case r.LogLevel.Error:console.error("["+(new Date).toISOString()+"] "+r.LogLevel[e]+": "+t);break;case r.LogLevel.Warning:console.warn("["+(new Date).toISOString()+"] "+r.LogLevel[e]+": "+t);break;case r.LogLevel.Information:console.info("["+(new Date).toISOString()+"] "+r.LogLevel[e]+": "+t);break;default:console.log("["+(new Date).toISOString()+"] "+r.LogLevel[e]+": "+t)}},e}();t.ConsoleLogger=i},function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,i){function a(e){try{c(r.next(e))}catch(e){i(e)}}function s(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(a,s)}c((r=r.apply(e,t||[])).next())})},o=this&&this.__generator||function(e,t){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=(o=a.trys).length>0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]0&&o[o.length-1])&&(6===i[0]||2===i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]>=7)>0&&(r|=128),n.push(r)}while(t>0);t=e.byteLength||e.length;var o=new Uint8Array(n.length+t);return o.set(n,0),o.set(e,n.length),o.buffer},e.parse=function(e){for(var t=[],n=new Uint8Array(e),r=[0,7,14,21,28],o=0;o7)throw new Error("Messages bigger than 2GB are not supported.");if(!(n.byteLength>=o+i+a))throw new Error("Incomplete message.");t.push(n.slice?n.slice(o+i,o+i+a):n.subarray(o+i,o+i+a)),o=o+i+a}return t},e}();var s=new Uint8Array([145,i.MessageType.Ping]),c=function(){function e(){this.name="messagepack",this.version=1,this.transferFormat=i.TransferFormat.Binary,this.errorResult=1,this.voidResult=2,this.nonVoidResult=3}return e.prototype.parseMessages=function(e,t){if(!(e instanceof r.Buffer||(n=e,n&&"undefined"!=typeof ArrayBuffer&&(n instanceof ArrayBuffer||n.constructor&&"ArrayBuffer"===n.constructor.name))))throw new Error("Invalid input for MessagePack hub protocol. Expected an ArrayBuffer or Buffer.");var n;null===t&&(t=i.NullLogger.instance);for(var o=[],s=0,c=a.parse(e);s0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return e[r]=[],e}function u(e,t,n){var a=e;if(e instanceof Comment&&(s(a)&&s(a).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(l(a))throw new Error("Not implemented: moving existing logical children");var i=s(t);if(n0;)e(r,0);var a=r;a.parentNode.removeChild(a)},t.getLogicalParent=l,t.getLogicalSiblingEnd=function(e){return e[a]||null},t.getLogicalChild=function(e,t){return s(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===c(e).namespaceURI},t.getLogicalChildrenArray=s,t.permuteLogicalChildren=function(e,t){var n=s(e);t.forEach(function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=l(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)}),t.forEach(function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):d(r,e)}),t.forEach(function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,a=r;a;){var i=a.nextSibling;if(n.insertBefore(a,t),a===o)break;a=i}n.removeChild(t)}),t.forEach(function(e){n[e.toSiblingIndex]=e.moveRangeStart})},t.getClosestDomElement=c},function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),t.dispatchEvent=function(e,t){if(!r)throw new Error("eventDispatcher not initialized. Call 'setEventDispatcher' to configure it.");return r(e,t)},t.setEventDispatcher=function(e){r=e}},,,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,a){function i(e){try{l(r.next(e))}catch(e){a(e)}}function u(e){try{l(r.throw(e))}catch(e){a(e)}}function l(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(i,u)}l((r=r.apply(e,t||[])).next())})},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=(o=i.trys).length>0&&o[o.length-1])&&(6===a[0]||2===a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]0&&o[o.length-1])&&(6===a[0]||2===a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]0&&o[o.length-1])&&(6===a[0]||2===a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]0&&o[o.length-1])&&(6===a[0]||2===a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]-1?a.substring(0,u):"",s=u>-1?a.substring(u+1):a,c=t.monoPlatform.findMethod(e,l,s,i);t.monoPlatform.callMethod(c,null,r)},callMethod:function(e,n,r){if(r.length>4)throw new Error("Currently, MonoPlatform supports passing a maximum of 4 arguments from JS to .NET. You tried to pass "+r.length+".");var o=Module.stackSave();try{for(var a=Module.stackAlloc(r.length),u=Module.stackAlloc(4),l=0;l>2,r=Module.HEAPU32[n+1];if(r>v)throw new Error("Cannot read uint64 with high order part "+r+", because the result would exceed Number.MAX_SAFE_INTEGER.");return r*h+Module.HEAPU32[n]},readFloatField:function(e,t){return Module.getValue(e+(t||0),"float")},readObjectField:function(e,t){return Module.getValue(e+(t||0),"i32")},readStringField:function(e,n){var r=Module.getValue(e+(n||0),"i32");return 0===r?null:t.monoPlatform.toJavaScriptString(r)},readStructField:function(e,t){return e+(t||0)}};var b=document.createElement("a");function w(e){return e+12}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(33),o=window.chrome&&navigator.userAgent.indexOf("Edge")<0,a=!1;function i(){return a&&o}t.hasDebuggingEnabled=i,t.attachDebuggerHotkey=function(e){a=e.some(function(e){return/\.pdb$/.test(r.getFileNameFromUrl(e))});var t=navigator.platform.match(/^Mac/i)?"Cmd":"Alt";i()&&console.info("Debugging hotkey: Shift+"+t+"+D (when application has focus)"),document.addEventListener("keydown",function(e){var t;e.shiftKey&&(e.metaKey||e.altKey)&&"KeyD"===e.code&&(a?o?((t=document.createElement("a")).href="_framework/debug?url="+encodeURIComponent(location.href),t.target="_blank",t.rel="noopener noreferrer",t.click()):console.error("Currently, only Chrome is supported for debugging."):console.error("Cannot start debugging, because the application was not compiled with debugging enabled."))})}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(9),o=function(){function e(e){this.batchAddress=e,this.arrayRangeReader=a,this.arrayBuilderSegmentReader=i,this.diffReader=u,this.editReader=l,this.frameReader=s}return e.prototype.updatedComponents=function(){return r.platform.readStructField(this.batchAddress,0)},e.prototype.referenceFrames=function(){return r.platform.readStructField(this.batchAddress,a.structLength)},e.prototype.disposedComponentIds=function(){return r.platform.readStructField(this.batchAddress,2*a.structLength)},e.prototype.disposedEventHandlerIds=function(){return r.platform.readStructField(this.batchAddress,3*a.structLength)},e.prototype.updatedComponentsEntry=function(e,t){return c(e,t,u.structLength)},e.prototype.referenceFramesEntry=function(e,t){return c(e,t,s.structLength)},e.prototype.disposedComponentIdsEntry=function(e,t){var n=c(e,t,4);return r.platform.readInt32Field(n)},e.prototype.disposedEventHandlerIdsEntry=function(e,t){var n=c(e,t,8);return r.platform.readUint64Field(n)},e}();t.SharedMemoryRenderBatch=o;var a={structLength:8,values:function(e){return r.platform.readObjectField(e,0)},count:function(e){return r.platform.readInt32Field(e,4)}},i={structLength:12,values:function(e){var t=r.platform.readObjectField(e,0),n=r.platform.getObjectFieldsBaseAddress(t);return r.platform.readObjectField(n,0)},offset:function(e){return r.platform.readInt32Field(e,4)},count:function(e){return r.platform.readInt32Field(e,8)}},u={structLength:4+i.structLength,componentId:function(e){return r.platform.readInt32Field(e,0)},edits:function(e){return r.platform.readStructField(e,4)},editsEntry:function(e,t){return c(e,t,l.structLength)}},l={structLength:20,editType:function(e){return r.platform.readInt32Field(e,0)},siblingIndex:function(e){return r.platform.readInt32Field(e,4)},newTreeIndex:function(e){return r.platform.readInt32Field(e,8)},moveToSiblingIndex:function(e){return r.platform.readInt32Field(e,8)},removedAttributeName:function(e){return r.platform.readStringField(e,16)}},s={structLength:36,frameType:function(e){return r.platform.readInt16Field(e,4)},subtreeLength:function(e){return r.platform.readInt32Field(e,8)},elementReferenceCaptureId:function(e){return r.platform.readStringField(e,16)},componentId:function(e){return r.platform.readInt32Field(e,12)},elementName:function(e){return r.platform.readStringField(e,16)},textContent:function(e){return r.platform.readStringField(e,16)},markupContent:function(e){return r.platform.readStringField(e,16)},attributeName:function(e){return r.platform.readStringField(e,16)},attributeValue:function(e){return r.platform.readStringField(e,24)},attributeEventHandlerId:function(e){return r.platform.readUint64Field(e,8)}};function c(e,t,n){return r.platform.getArrayEntryPtr(e,t,n)}}]); \ No newline at end of file +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=45)}([,,,,,,,,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),n(25),n(9);var r=n(26),o=n(16),a={},i=!1;function u(e,t,n){var o=a[e];o||(o=a[e]=new r.BrowserRenderer(e)),o.attachRootComponentToLogicalElement(n,t)}t.attachRootComponentToLogicalElement=u,t.attachRootComponentToElement=function(e,t,n){var r=document.querySelector(e);if(!r)throw new Error("Could not find any element matching selector '"+e+"'.");u(n||0,o.toLogicalElement(r,!0),t)},t.renderBatch=function(e,t){var n=a[e];if(!n)throw new Error("There is no browser renderer with ID "+e+".");for(var r=t.arrayRangeReader,o=t.updatedComponents(),u=r.values(o),l=r.count(o),s=t.referenceFrames(),c=r.values(s),f=t.diffReader,d=0;d0&&!t)throw new Error("New logical elements must start empty, or allowExistingContents must be true");return e[r]=[],e}function u(e,t,n){var a=e;if(e instanceof Comment&&(s(a)&&s(a).length>0))throw new Error("Not implemented: inserting non-empty logical container");if(l(a))throw new Error("Not implemented: moving existing logical children");var i=s(t);if(n0;)e(r,0);var a=r;a.parentNode.removeChild(a)},t.getLogicalParent=l,t.getLogicalSiblingEnd=function(e){return e[a]||null},t.getLogicalChild=function(e,t){return s(e)[t]},t.isSvgElement=function(e){return"http://www.w3.org/2000/svg"===c(e).namespaceURI},t.getLogicalChildrenArray=s,t.permuteLogicalChildren=function(e,t){var n=s(e);t.forEach(function(e){e.moveRangeStart=n[e.fromSiblingIndex],e.moveRangeEnd=function e(t){if(t instanceof Element)return t;var n=f(t);if(n)return n.previousSibling;var r=l(t);return r instanceof Element?r.lastChild:e(r)}(e.moveRangeStart)}),t.forEach(function(t){var r=t.moveToBeforeMarker=document.createComment("marker"),o=n[t.toSiblingIndex+1];o?o.parentNode.insertBefore(r,o):d(r,e)}),t.forEach(function(e){for(var t=e.moveToBeforeMarker,n=t.parentNode,r=e.moveRangeStart,o=e.moveRangeEnd,a=r;a;){var i=a.nextSibling;if(n.insertBefore(a,t),a===o)break;a=i}n.removeChild(t)}),t.forEach(function(e){n[e.toSiblingIndex]=e.moveRangeStart})},t.getClosestDomElement=c},function(e,t,n){"use strict";var r;Object.defineProperty(t,"__esModule",{value:!0}),t.dispatchEvent=function(e,t){if(!r)throw new Error("eventDispatcher not initialized. Call 'setEventDispatcher' to configure it.");return r(e,t)},t.setEventDispatcher=function(e){r=e}},,,,function(e,t,n){"use strict";var r=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,a){function i(e){try{l(r.next(e))}catch(e){a(e)}}function u(e){try{l(r.throw(e))}catch(e){a(e)}}function l(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(i,u)}l((r=r.apply(e,t||[])).next())})},o=this&&this.__generator||function(e,t){var n,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:u(0),throw:u(1),return:u(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function u(a){return function(u){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return i.label++,{value:a[1],done:!1};case 5:i.label++,r=a[1],a=[0];continue;case 7:a=i.ops.pop(),i.trys.pop();continue;default:if(!(o=(o=i.trys).length>0&&o[o.length-1])&&(6===a[0]||2===a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]0&&o[o.length-1])&&(6===a[0]||2===a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]0&&o[o.length-1])&&(6===a[0]||2===a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]0&&o[o.length-1])&&(6===a[0]||2===a[0])){i=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]-1?a.substring(0,u):"",s=u>-1?a.substring(u+1):a,c=t.monoPlatform.findMethod(e,l,s,i);t.monoPlatform.callMethod(c,null,r)},callMethod:function(e,n,r){if(r.length>4)throw new Error("Currently, MonoPlatform supports passing a maximum of 4 arguments from JS to .NET. You tried to pass "+r.length+".");var o=Module.stackSave();try{for(var a=Module.stackAlloc(r.length),u=Module.stackAlloc(4),l=0;l>2,r=Module.HEAPU32[n+1];if(r>v)throw new Error("Cannot read uint64 with high order part "+r+", because the result would exceed Number.MAX_SAFE_INTEGER.");return r*h+Module.HEAPU32[n]},readFloatField:function(e,t){return Module.getValue(e+(t||0),"float")},readObjectField:function(e,t){return Module.getValue(e+(t||0),"i32")},readStringField:function(e,n){var r=Module.getValue(e+(n||0),"i32");return 0===r?null:t.monoPlatform.toJavaScriptString(r)},readStructField:function(e,t){return e+(t||0)}};var b=document.createElement("a");function w(e){return e+12}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(33),o=window.chrome&&navigator.userAgent.indexOf("Edge")<0,a=!1;function i(){return a&&o}t.hasDebuggingEnabled=i,t.attachDebuggerHotkey=function(e){a=e.some(function(e){return/\.pdb$/.test(r.getFileNameFromUrl(e))});var t=navigator.platform.match(/^Mac/i)?"Cmd":"Alt";i()&&console.info("Debugging hotkey: Shift+"+t+"+D (when application has focus)"),document.addEventListener("keydown",function(e){var t;e.shiftKey&&(e.metaKey||e.altKey)&&"KeyD"===e.code&&(a?o?((t=document.createElement("a")).href="_framework/debug?url="+encodeURIComponent(location.href),t.target="_blank",t.rel="noopener noreferrer",t.click()):console.error("Currently, only Chrome is supported for debugging."):console.error("Cannot start debugging, because the application was not compiled with debugging enabled."))})}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(9),o=function(){function e(e){this.batchAddress=e,this.arrayRangeReader=a,this.arrayBuilderSegmentReader=i,this.diffReader=u,this.editReader=l,this.frameReader=s}return e.prototype.updatedComponents=function(){return r.platform.readStructField(this.batchAddress,0)},e.prototype.referenceFrames=function(){return r.platform.readStructField(this.batchAddress,a.structLength)},e.prototype.disposedComponentIds=function(){return r.platform.readStructField(this.batchAddress,2*a.structLength)},e.prototype.disposedEventHandlerIds=function(){return r.platform.readStructField(this.batchAddress,3*a.structLength)},e.prototype.updatedComponentsEntry=function(e,t){return c(e,t,u.structLength)},e.prototype.referenceFramesEntry=function(e,t){return c(e,t,s.structLength)},e.prototype.disposedComponentIdsEntry=function(e,t){var n=c(e,t,4);return r.platform.readInt32Field(n)},e.prototype.disposedEventHandlerIdsEntry=function(e,t){var n=c(e,t,8);return r.platform.readUint64Field(n)},e}();t.SharedMemoryRenderBatch=o;var a={structLength:8,values:function(e){return r.platform.readObjectField(e,0)},count:function(e){return r.platform.readInt32Field(e,4)}},i={structLength:12,values:function(e){var t=r.platform.readObjectField(e,0),n=r.platform.getObjectFieldsBaseAddress(t);return r.platform.readObjectField(n,0)},offset:function(e){return r.platform.readInt32Field(e,4)},count:function(e){return r.platform.readInt32Field(e,8)}},u={structLength:4+i.structLength,componentId:function(e){return r.platform.readInt32Field(e,0)},edits:function(e){return r.platform.readStructField(e,4)},editsEntry:function(e,t){return c(e,t,l.structLength)}},l={structLength:20,editType:function(e){return r.platform.readInt32Field(e,0)},siblingIndex:function(e){return r.platform.readInt32Field(e,4)},newTreeIndex:function(e){return r.platform.readInt32Field(e,8)},moveToSiblingIndex:function(e){return r.platform.readInt32Field(e,8)},removedAttributeName:function(e){return r.platform.readStringField(e,16)}},s={structLength:36,frameType:function(e){return r.platform.readInt16Field(e,4)},subtreeLength:function(e){return r.platform.readInt32Field(e,8)},elementReferenceCaptureId:function(e){return r.platform.readStringField(e,16)},componentId:function(e){return r.platform.readInt32Field(e,12)},elementName:function(e){return r.platform.readStringField(e,16)},textContent:function(e){return r.platform.readStringField(e,16)},markupContent:function(e){return r.platform.readStringField(e,16)},attributeName:function(e){return r.platform.readStringField(e,16)},attributeValue:function(e){return r.platform.readStringField(e,24)},attributeEventHandlerId:function(e){return r.platform.readUint64Field(e,8)}};function c(e,t,n){return r.platform.getArrayEntryPtr(e,t,n)}}]); \ No newline at end of file diff --git a/src/Components/Web.JS/src/Boot.Server.ts b/src/Components/Web.JS/src/Boot.Server.ts index e52113d7ac..b4135fc503 100644 --- a/src/Components/Web.JS/src/Boot.Server.ts +++ b/src/Components/Web.JS/src/Boot.Server.ts @@ -85,12 +85,11 @@ async function initializeConnection(options: BlazorOptions, logger: Logger): Pro connection.on('JS.BeginInvokeJS', DotNet.jsCallDispatcher.beginInvokeJSFromDotNet); connection.on('JS.EndInvokeDotNet', (args: string) => DotNet.jsCallDispatcher.endInvokeDotNetFromJS(...(JSON.parse(args) as [string, boolean, unknown]))); - connection.on('JS.RenderBatch', (browserRendererId: number, batchId: number, batchData: Uint8Array) => { - logger.log(LogLevel.Debug, `Received render batch for ${browserRendererId} with id ${batchId} and ${batchData.byteLength} bytes.`); - const queue = RenderQueue.getOrCreateQueue(browserRendererId, logger); - - queue.processBatch(batchId, batchData, connection); + const renderQueue = new RenderQueue(/* renderer ID unused with remote renderer */ 0, logger); + connection.on('JS.RenderBatch', (batchId: number, batchData: Uint8Array) => { + logger.log(LogLevel.Debug, `Received render batch with id ${batchId} and ${batchData.byteLength} bytes.`); + renderQueue.processBatch(batchId, batchData, connection); }); connection.onclose(error => !renderingFailed && options.reconnectionHandler!.onConnectionDown(options.reconnectionOptions, error)); diff --git a/src/Components/Web.JS/src/Boot.WebAssembly.ts b/src/Components/Web.JS/src/Boot.WebAssembly.ts index ee990a10c2..849721b20b 100644 --- a/src/Components/Web.JS/src/Boot.WebAssembly.ts +++ b/src/Components/Web.JS/src/Boot.WebAssembly.ts @@ -18,7 +18,7 @@ async function boot(options?: any): Promise { } started = true; - setEventDispatcher((eventDescriptor, eventArgs) => DotNet.invokeMethodAsync('Microsoft.AspNetCore.Components.Web', 'DispatchEvent', eventDescriptor, JSON.stringify(eventArgs))); + setEventDispatcher((eventDescriptor, eventArgs) => DotNet.invokeMethodAsync('Microsoft.AspNetCore.Blazor', 'DispatchEvent', eventDescriptor, JSON.stringify(eventArgs))); // Configure environment for execution under Mono WebAssembly with shared-memory rendering const platform = Environment.setPlatform(monoPlatform); diff --git a/src/Components/Web.JS/src/Platform/Circuits/RenderQueue.ts b/src/Components/Web.JS/src/Platform/Circuits/RenderQueue.ts index 78860d111c..24c22a09ee 100644 --- a/src/Components/Web.JS/src/Platform/Circuits/RenderQueue.ts +++ b/src/Components/Web.JS/src/Platform/Circuits/RenderQueue.ts @@ -4,8 +4,6 @@ import { Logger, LogLevel } from '../Logging/Logger'; import { HubConnection } from '@aspnet/signalr'; export class RenderQueue { - private static renderQueues = new Map(); - private nextBatchId = 2; private fatalError?: string; @@ -19,17 +17,6 @@ export class RenderQueue { this.logger = logger; } - public static getOrCreateQueue(browserRendererId: number, logger: Logger): RenderQueue { - const queue = this.renderQueues.get(browserRendererId); - if (queue) { - return queue; - } - - const newQueue = new RenderQueue(browserRendererId, logger); - this.renderQueues.set(browserRendererId, newQueue); - return newQueue; - } - public async processBatch(receivedBatchId: number, batchData: Uint8Array, connection: HubConnection): Promise { if (receivedBatchId < this.nextBatchId) { // SignalR delivers messages in order, but it does not guarantee that the message gets delivered. diff --git a/src/Components/Web.JS/src/Rendering/Renderer.ts b/src/Components/Web.JS/src/Rendering/Renderer.ts index 88a21d16a6..06b8ba3985 100644 --- a/src/Components/Web.JS/src/Rendering/Renderer.ts +++ b/src/Components/Web.JS/src/Rendering/Renderer.ts @@ -12,7 +12,6 @@ const browserRenderers: BrowserRendererRegistry = {}; let shouldResetScrollAfterNextBatch = false; export function attachRootComponentToLogicalElement(browserRendererId: number, logicalElement: LogicalElement, componentId: number): void { - let browserRenderer = browserRenderers[browserRendererId]; if (!browserRenderer) { browserRenderer = browserRenderers[browserRendererId] = new BrowserRenderer(browserRendererId); @@ -21,15 +20,15 @@ export function attachRootComponentToLogicalElement(browserRendererId: number, l browserRenderer.attachRootComponentToLogicalElement(componentId, logicalElement); } -export function attachRootComponentToElement(browserRendererId: number, elementSelector: string, componentId: number): void { - +export function attachRootComponentToElement(elementSelector: string, componentId: number, browserRendererId?: number): void { const element = document.querySelector(elementSelector); if (!element) { throw new Error(`Could not find any element matching selector '${elementSelector}'.`); } // 'allowExistingContents' to keep any prerendered content until we do the first client-side render - attachRootComponentToLogicalElement(browserRendererId, toLogicalElement(element, /* allow existing contents */ true), componentId); + // Only client-side Blazor supplies a browser renderer ID + attachRootComponentToLogicalElement(browserRendererId || 0, toLogicalElement(element, /* allow existing contents */ true), componentId); } export function renderBatch(browserRendererId: number, batch: RenderBatch): void { diff --git a/src/Components/Web.JS/tests/RenderQueue.test.ts b/src/Components/Web.JS/tests/RenderQueue.test.ts index df22da3a8a..81e283fc0d 100644 --- a/src/Components/Web.JS/tests/RenderQueue.test.ts +++ b/src/Components/Web.JS/tests/RenderQueue.test.ts @@ -10,23 +10,8 @@ jest.mock('../src/Rendering/Renderer', () => ({ describe('RenderQueue', () => { - it('getOrCreateRenderQueue returns a new queue if one does not exist for a renderer', () => { - const queue = RenderQueue.getOrCreateQueue(1, NullLogger.instance); - - expect(queue).toBeDefined(); - - }); - - it('getOrCreateRenderQueue returns an existing queue if one exists for a renderer', () => { - const queue = RenderQueue.getOrCreateQueue(2, NullLogger.instance); - const secondQueue = RenderQueue.getOrCreateQueue(2, NullLogger.instance); - - expect(secondQueue).toBe(queue); - - }); - it('processBatch acknowledges previously rendered batches', () => { - const queue = RenderQueue.getOrCreateQueue(3, NullLogger.instance); + const queue = new RenderQueue(0, NullLogger.instance); const sendMock = jest.fn(); const connection = { send: sendMock } as any as signalR.HubConnection; @@ -37,7 +22,7 @@ describe('RenderQueue', () => { }); it('processBatch does not render out of order batches', () => { - const queue = RenderQueue.getOrCreateQueue(4, NullLogger.instance); + const queue = new RenderQueue(0, NullLogger.instance); const sendMock = jest.fn(); const connection = { send: sendMock } as any as signalR.HubConnection; @@ -47,7 +32,7 @@ describe('RenderQueue', () => { }); it('processBatch renders pending batches', () => { - const queue = RenderQueue.getOrCreateQueue(5, NullLogger.instance); + const queue = new RenderQueue(0, NullLogger.instance); const sendMock = jest.fn(); const connection = { send: sendMock } as any as signalR.HubConnection; diff --git a/src/Components/Web/ref/Microsoft.AspNetCore.Components.Web.netstandard2.0.cs b/src/Components/Web/ref/Microsoft.AspNetCore.Components.Web.netstandard2.0.cs index 7982f2e7b3..f6a30257c2 100644 --- a/src/Components/Web/ref/Microsoft.AspNetCore.Components.Web.netstandard2.0.cs +++ b/src/Components/Web/ref/Microsoft.AspNetCore.Components.Web.netstandard2.0.cs @@ -308,25 +308,25 @@ namespace Microsoft.AspNetCore.Components.Forms protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } protected override void OnParametersSet() { } } - public abstract partial class InputBase : Microsoft.AspNetCore.Components.ComponentBase + public abstract partial class InputBase : Microsoft.AspNetCore.Components.ComponentBase { protected InputBase() { } [Microsoft.AspNetCore.Components.ParameterAttribute(CaptureUnmatchedValues=true)] public System.Collections.Generic.IReadOnlyDictionary AdditionalAttributes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } protected string CssClass { get { throw null; } } - protected T CurrentValue { get { throw null; } set { } } + protected TValue CurrentValue { get { throw null; } set { } } protected string CurrentValueAsString { get { throw null; } set { } } protected Microsoft.AspNetCore.Components.Forms.EditContext EditContext { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } protected Microsoft.AspNetCore.Components.Forms.FieldIdentifier FieldIdentifier { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } [Microsoft.AspNetCore.Components.ParameterAttribute] - public T Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public TValue Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } [Microsoft.AspNetCore.Components.ParameterAttribute] - public Microsoft.AspNetCore.Components.EventCallback ValueChanged { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public Microsoft.AspNetCore.Components.EventCallback ValueChanged { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Linq.Expressions.Expression> ValueExpression { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - protected virtual string FormatValueAsString(T value) { throw null; } + public System.Linq.Expressions.Expression> ValueExpression { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + protected virtual string FormatValueAsString(TValue value) { throw null; } public override System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) { throw null; } - protected abstract bool TryParseValueFromString(string value, out T result, out string validationErrorMessage); + protected abstract bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage); } public partial class InputCheckbox : Microsoft.AspNetCore.Components.Forms.InputBase { @@ -334,31 +334,31 @@ namespace Microsoft.AspNetCore.Components.Forms protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } protected override bool TryParseValueFromString(string value, out bool result, out string validationErrorMessage) { throw null; } } - public partial class InputDate : Microsoft.AspNetCore.Components.Forms.InputBase + public partial class InputDate : Microsoft.AspNetCore.Components.Forms.InputBase { public InputDate() { } [Microsoft.AspNetCore.Components.ParameterAttribute] public string ParsingErrorMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - protected override string FormatValueAsString(T value) { throw null; } - protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage) { throw null; } + protected override string FormatValueAsString(TValue value) { throw null; } + protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { throw null; } } - public partial class InputNumber : Microsoft.AspNetCore.Components.Forms.InputBase + public partial class InputNumber : Microsoft.AspNetCore.Components.Forms.InputBase { public InputNumber() { } [Microsoft.AspNetCore.Components.ParameterAttribute] public string ParsingErrorMessage { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - protected override string FormatValueAsString(T value) { throw null; } - protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage) { throw null; } + protected override string FormatValueAsString(TValue value) { throw null; } + protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { throw null; } } - public partial class InputSelect : Microsoft.AspNetCore.Components.Forms.InputBase + public partial class InputSelect : Microsoft.AspNetCore.Components.Forms.InputBase { public InputSelect() { } [Microsoft.AspNetCore.Components.ParameterAttribute] public Microsoft.AspNetCore.Components.RenderFragment ChildContent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } - protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage) { throw null; } + protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { throw null; } } public partial class InputText : Microsoft.AspNetCore.Components.Forms.InputBase { @@ -372,13 +372,13 @@ namespace Microsoft.AspNetCore.Components.Forms protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage) { throw null; } } - public partial class ValidationMessage : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable + public partial class ValidationMessage : Microsoft.AspNetCore.Components.ComponentBase, System.IDisposable { public ValidationMessage() { } [Microsoft.AspNetCore.Components.ParameterAttribute(CaptureUnmatchedValues=true)] public System.Collections.Generic.IReadOnlyDictionary AdditionalAttributes { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } [Microsoft.AspNetCore.Components.ParameterAttribute] - public System.Linq.Expressions.Expression> For { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public System.Linq.Expressions.Expression> For { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } protected virtual void Dispose(bool disposing) { } protected override void OnParametersSet() { } @@ -422,17 +422,12 @@ namespace Microsoft.AspNetCore.Components.Routing } namespace Microsoft.AspNetCore.Components.Web { - public static partial class RendererRegistryEventDispatcher + public sealed partial class WebEventDescriptor { - [Microsoft.JSInterop.JSInvokableAttribute("DispatchEvent")] - public static System.Threading.Tasks.Task DispatchEvent(Microsoft.AspNetCore.Components.Web.RendererRegistryEventDispatcher.BrowserEventDescriptor eventDescriptor, string eventArgsJson) { throw null; } - public partial class BrowserEventDescriptor - { - public BrowserEventDescriptor() { } - public int BrowserRendererId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public string EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public Microsoft.AspNetCore.Components.Rendering.EventFieldInfo EventFieldInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - public ulong EventHandlerId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } - } + public WebEventDescriptor() { } + public int BrowserRendererId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public string EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public Microsoft.AspNetCore.Components.Rendering.EventFieldInfo EventFieldInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public ulong EventHandlerId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } } } diff --git a/src/Components/Web/src/Forms/InputBase.cs b/src/Components/Web/src/Forms/InputBase.cs index 4202aec396..f60c330326 100644 --- a/src/Components/Web/src/Forms/InputBase.cs +++ b/src/Components/Web/src/Forms/InputBase.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Components.Forms /// integrates with an , which must be supplied /// as a cascading parameter. /// - public abstract class InputBase : ComponentBase + public abstract class InputBase : ComponentBase { private bool _previousParsingAttemptFailed; private ValidationMessageStore _parsingValidationMessages; @@ -32,20 +32,20 @@ namespace Microsoft.AspNetCore.Components.Forms /// /// @bind-Value="model.PropertyName" /// - [Parameter] public T Value { get; set; } + [Parameter] public TValue Value { get; set; } /// /// Gets or sets a callback that updates the bound value. /// - [Parameter] public EventCallback ValueChanged { get; set; } + [Parameter] public EventCallback ValueChanged { get; set; } /// /// Gets or sets an expression that identifies the bound value. /// - [Parameter] public Expression> ValueExpression { get; set; } + [Parameter] public Expression> ValueExpression { get; set; } /// - /// Gets the associated . + /// Gets the associated . /// protected EditContext EditContext { get; set; } @@ -57,12 +57,12 @@ namespace Microsoft.AspNetCore.Components.Forms /// /// Gets or sets the current value of the input. /// - protected T CurrentValue + protected TValue CurrentValue { get => Value; set { - var hasChanged = !EqualityComparer.Default.Equals(value, Value); + var hasChanged = !EqualityComparer.Default.Equals(value, Value); if (hasChanged) { Value = value; @@ -126,18 +126,18 @@ namespace Microsoft.AspNetCore.Components.Forms /// /// The value to format. /// A string representation of the value. - protected virtual string FormatValueAsString(T value) + protected virtual string FormatValueAsString(TValue value) => value?.ToString(); /// - /// Parses a string to create an instance of . Derived classes can override this to change how + /// Parses a string to create an instance of . Derived classes can override this to change how /// interprets incoming values. /// /// The string value to be parsed. - /// An instance of . + /// An instance of . /// If the value could not be parsed, provides a validation error message. /// True if the value could be parsed; otherwise false. - protected abstract bool TryParseValueFromString(string value, out T result, out string validationErrorMessage); + protected abstract bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage); /// /// Gets a string that indicates the status of the field being edited. This will include @@ -192,7 +192,7 @@ namespace Microsoft.AspNetCore.Components.Forms EditContext = CascadedEditContext; FieldIdentifier = FieldIdentifier.Create(ValueExpression); - _nullableUnderlyingType = Nullable.GetUnderlyingType(typeof(T)); + _nullableUnderlyingType = Nullable.GetUnderlyingType(typeof(TValue)); } else if (CascadedEditContext != EditContext) { diff --git a/src/Components/Web/src/Forms/InputDate.cs b/src/Components/Web/src/Forms/InputDate.cs index 32f6800519..7192523471 100644 --- a/src/Components/Web/src/Forms/InputDate.cs +++ b/src/Components/Web/src/Forms/InputDate.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Components.Forms /// An input component for editing date values. /// Supported types are and . /// - public class InputDate : InputBase + public class InputDate : InputBase { private const string DateFormat = "yyyy-MM-dd"; // Compatible with HTML date inputs @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Components.Forms } /// - protected override string FormatValueAsString(T value) + protected override string FormatValueAsString(TValue value) { switch (value) { @@ -47,11 +47,11 @@ namespace Microsoft.AspNetCore.Components.Forms } /// - protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage) + protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { // Unwrap nullable types. We don't have to deal with receiving empty values for nullable // types here, because the underlying InputBase already covers that. - var targetType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); + var targetType = Nullable.GetUnderlyingType(typeof(TValue)) ?? typeof(TValue); bool success; if (targetType == typeof(DateTime)) @@ -79,12 +79,12 @@ namespace Microsoft.AspNetCore.Components.Forms } } - static bool TryParseDateTime(string value, out T result) + static bool TryParseDateTime(string value, out TValue result) { var success = BindConverter.TryConvertToDateTime(value, CultureInfo.InvariantCulture, DateFormat, out var parsedValue); if (success) { - result = (T)(object)parsedValue; + result = (TValue)(object)parsedValue; return true; } else @@ -94,12 +94,12 @@ namespace Microsoft.AspNetCore.Components.Forms } } - static bool TryParseDateTimeOffset(string value, out T result) + static bool TryParseDateTimeOffset(string value, out TValue result) { var success = BindConverter.TryConvertToDateTimeOffset(value, CultureInfo.InvariantCulture, DateFormat, out var parsedValue); if (success) { - result = (T)(object)parsedValue; + result = (TValue)(object)parsedValue; return true; } else diff --git a/src/Components/Web/src/Forms/InputNumber.cs b/src/Components/Web/src/Forms/InputNumber.cs index 780028aa25..4f0377ceed 100644 --- a/src/Components/Web/src/Forms/InputNumber.cs +++ b/src/Components/Web/src/Forms/InputNumber.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Components.Forms /// An input component for editing numeric values. /// Supported numeric types are , , , , . /// - public class InputNumber : InputBase + public class InputNumber : InputBase { private static string _stepAttributeValue; // Null by default, so only allows whole numbers as per HTML spec @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Components.Forms { // Unwrap Nullable, because InputBase already deals with the Nullable aspect // of it for us. We will only get asked to parse the T for nonempty inputs. - var targetType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); + var targetType = Nullable.GetUnderlyingType(typeof(TValue)) ?? typeof(TValue); if (targetType == typeof(int) || targetType == typeof(float) || targetType == typeof(double) || @@ -52,9 +52,9 @@ namespace Microsoft.AspNetCore.Components.Forms } /// - protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage) + protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { - if (BindConverter.TryConvertTo(value, CultureInfo.InvariantCulture, out result)) + if (BindConverter.TryConvertTo(value, CultureInfo.InvariantCulture, out result)) { validationErrorMessage = null; return true; @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Components.Forms /// /// The value to format. /// A string representation of the value. - protected override string FormatValueAsString(T value) + protected override string FormatValueAsString(TValue value) { // Avoiding a cast to IFormattable to avoid boxing. switch (value) diff --git a/src/Components/Web/src/Forms/InputSelect.cs b/src/Components/Web/src/Forms/InputSelect.cs index 91ec034f36..b8cdbeab1f 100644 --- a/src/Components/Web/src/Forms/InputSelect.cs +++ b/src/Components/Web/src/Forms/InputSelect.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Components.Forms /// /// A dropdown selection component. /// - public class InputSelect : InputBase + public class InputSelect : InputBase { /// /// Gets or sets the child content to be rendering inside the select element. @@ -30,17 +30,17 @@ namespace Microsoft.AspNetCore.Components.Forms } /// - protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage) + protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { - if (typeof(T) == typeof(string)) + if (typeof(TValue) == typeof(string)) { - result = (T)(object)value; + result = (TValue)(object)value; validationErrorMessage = null; return true; } - else if (typeof(T).IsEnum) + else if (typeof(TValue).IsEnum) { - var success = BindConverter.TryConvertTo(value, CultureInfo.CurrentCulture, out var parsedValue); + var success = BindConverter.TryConvertTo(value, CultureInfo.CurrentCulture, out var parsedValue); if (success) { result = parsedValue; @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Components.Forms } } - throw new InvalidOperationException($"{GetType()} does not support the type '{typeof(T)}'."); + throw new InvalidOperationException($"{GetType()} does not support the type '{typeof(TValue)}'."); } } } diff --git a/src/Components/Web/src/Forms/ValidationMessage.cs b/src/Components/Web/src/Forms/ValidationMessage.cs index 53b8057ff7..d033fdba20 100644 --- a/src/Components/Web/src/Forms/ValidationMessage.cs +++ b/src/Components/Web/src/Forms/ValidationMessage.cs @@ -11,10 +11,10 @@ namespace Microsoft.AspNetCore.Components.Forms /// /// Displays a list of validation messages for a specified field within a cascaded . /// - public class ValidationMessage : ComponentBase, IDisposable + public class ValidationMessage : ComponentBase, IDisposable { private EditContext _previousEditContext; - private Expression> _previousFieldAccessor; + private Expression> _previousFieldAccessor; private readonly EventHandler _validationStateChangedHandler; private FieldIdentifier _fieldIdentifier; @@ -28,10 +28,10 @@ namespace Microsoft.AspNetCore.Components.Forms /// /// Specifies the field for which validation messages should be displayed. /// - [Parameter] public Expression> For { get; set; } + [Parameter] public Expression> For { get; set; } /// ` - /// Constructs an instance of . + /// Constructs an instance of . /// public ValidationMessage() { diff --git a/src/Components/Web/src/Properties/AssemblyInfo.cs b/src/Components/Web/src/Properties/AssemblyInfo.cs index c773cb61e9..2741560028 100644 --- a/src/Components/Web/src/Properties/AssemblyInfo.cs +++ b/src/Components/Web/src/Properties/AssemblyInfo.cs @@ -1,6 +1,3 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Blazor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] -[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Server, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] - [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Components.Server.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Components/Web/src/RendererRegistry.cs b/src/Components/Web/src/RendererRegistry.cs deleted file mode 100644 index 74926d8d0e..0000000000 --- a/src/Components/Web/src/RendererRegistry.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Components.Rendering; -using System.Collections.Generic; -using System.Threading; - -namespace Microsoft.AspNetCore.Components.Web -{ - // Provides mechanisms for locating instances - // by ID. This is used when receiving incoming events. It also implicitly - // roots instances and their associated component instances - // so they cannot be GCed while they are still registered for events. - - /// - /// Framework infrastructure, not intended to be used by application code. - /// - internal class RendererRegistry - { - private static AsyncLocal _current; - private static readonly RendererRegistry _globalRegistry; - - // By default the registry will be set to a default value. This means that - // things will 'just work when running in the browser. - // - // Running in Server-Side Components - any call into the Circuit will set this value via - // the async local. This will ensure that the incoming call can resolve the correct - // renderer associated with the user context. - static RendererRegistry() - { - _current = new AsyncLocal(); - _globalRegistry = new RendererRegistry(); - } - - /// - /// Framework infrastructure, not intended to be used by application code. - /// - public static RendererRegistry Current => _current.Value ?? _globalRegistry; - - /// - /// Framework infrastructure, not intended by used by application code. - /// - public static void SetCurrentRendererRegistry(RendererRegistry registry) - { - _current.Value = registry; - } - - private int _nextId; - private IDictionary _renderers = new Dictionary(); - - - /// - /// Framework infrastructure, not intended by used by application code. - /// - public int Add(Renderer renderer) - { - lock (_renderers) - { - var id = _nextId++; - _renderers.Add(id, renderer); - return id; - } - } - - /// - /// Framework infrastructure, not intended by used by application code. - /// - public Renderer Find(int rendererId) - { - lock (_renderers) - { - return _renderers[rendererId]; - } - } - - /// - /// Framework infrastructure, not intended by used by application code. - /// - public bool TryRemove(int rendererId) - { - lock (_renderers) - { - if (_renderers.ContainsKey(rendererId)) - { - _renderers.Remove(rendererId); - return true; - } - else - { - return false; - } - } - } - } -} diff --git a/src/Components/Web/src/WebEventDescriptor.cs b/src/Components/Web/src/WebEventDescriptor.cs new file mode 100644 index 0000000000..7b32c9b8a9 --- /dev/null +++ b/src/Components/Web/src/WebEventDescriptor.cs @@ -0,0 +1,38 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Components.Rendering; + +namespace Microsoft.AspNetCore.Components.Web +{ + /// + /// For framework use only. + /// + public sealed class WebEventDescriptor + { + // We split the incoming event data in two, because we don't know what type + // to use when deserializing the args until we've deserialized the descriptor. + // This class represents the first half of the parsing process. + // It's public only because it's part of the signature of a [JSInvokable] method. + + /// + /// For framework use only. + /// + public int BrowserRendererId { get; set; } + + /// + /// For framework use only. + /// + public ulong EventHandlerId { get; set; } + + /// + /// For framework use only. + /// + public string EventArgsType { get; set; } + + /// + /// For framework use only. + /// + public EventFieldInfo EventFieldInfo { get; set; } + } +} diff --git a/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs b/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs index deb353dd9c..3984f32d43 100644 --- a/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs +++ b/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests private void CreateDefaultConfiguration() { Client = new BlazorClient() { DefaultLatencyTimeout = DefaultLatencyTimeout }; - Client.RenderBatchReceived += (id, rendererId, data) => Batches.Add(new Batch(id, rendererId, data)); + Client.RenderBatchReceived += (id, data) => Batches.Add(new Batch(id, data)); Client.OnCircuitError += (error) => Errors.Add(error); _ = _serverFixture.RootUri; // this is needed for the side-effects of getting the URI. @@ -267,15 +267,13 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests private class Batch { - public Batch(int id, int rendererId, byte [] data) + public Batch(int id, byte [] data) { Id = id; - RendererId = rendererId; Data = data; } public int Id { get; } - public int RendererId { get; } public byte[] Data { get; } } } diff --git a/src/Components/test/E2ETest/ServerExecutionTests/InteropReliabilityTests.cs b/src/Components/test/E2ETest/ServerExecutionTests/InteropReliabilityTests.cs index c3ad07d7e4..ee4f4a00ed 100644 --- a/src/Components/test/E2ETest/ServerExecutionTests/InteropReliabilityTests.cs +++ b/src/Components/test/E2ETest/ServerExecutionTests/InteropReliabilityTests.cs @@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests await ValidateClientKeepsWorking(Client, batches); } - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12940")] public async Task CannotInvokeJSInvokableMethodsWithWrongNumberOfArguments() { // Arrange @@ -259,7 +259,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests await ValidateClientKeepsWorking(Client, batches); } - [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12962")] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12940")] public async Task LogsJSInteropCompletionsCallbacksAndContinuesWorkingInAllSituations() { // Arrange @@ -386,7 +386,30 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests null); Assert.Contains( - (LogLevel.Debug, "DispatchEventFailedToParseEventDescriptor"), + (LogLevel.Debug, "DispatchEventFailedToParseEventData"), + logEvents); + + await ValidateClientKeepsWorking(Client, batches); + } + + [Fact] + public async Task DispatchingEventsWithInvalidEventDescriptor() + { + // Arrange + var (interopCalls, dotNetCompletions, batches) = ConfigureClient(); + await GoToTestComponent(batches); + var sink = _serverFixture.Host.Services.GetRequiredService(); + var logEvents = new List<(LogLevel logLevel, string)>(); + sink.MessageLogged += (wc) => logEvents.Add((wc.LogLevel, wc.EventId.Name)); + + // Act + await Client.HubConnection.InvokeAsync( + "DispatchBrowserEvent", + "{Invalid:{\"payload}", + "{}"); + + Assert.Contains( + (LogLevel.Debug, "DispatchEventFailedToParseEventData"), logEvents); await ValidateClientKeepsWorking(Client, batches); @@ -403,7 +426,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests sink.MessageLogged += (wc) => logEvents.Add((wc.LogLevel, wc.EventId.Name)); // Act - var browserDescriptor = new RendererRegistryEventDispatcher.BrowserEventDescriptor() + var browserDescriptor = new WebEventDescriptor() { BrowserRendererId = 0, EventHandlerId = 6, @@ -416,13 +439,13 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests "{Invalid:{\"payload}"); Assert.Contains( - (LogLevel.Debug, "DispatchEventFailedToDispatchEvent"), + (LogLevel.Debug, "DispatchEventFailedToParseEventData"), logEvents); await ValidateClientKeepsWorking(Client, batches); } - [Fact] + [Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12940")] public async Task DispatchingEventsWithInvalidEventHandlerId() { // Arrange @@ -438,7 +461,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests Type = "click", Detail = 1 }; - var browserDescriptor = new RendererRegistryEventDispatcher.BrowserEventDescriptor() + var browserDescriptor = new WebEventDescriptor() { BrowserRendererId = 0, EventHandlerId = 1, @@ -458,47 +481,6 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests await ValidateClientKeepsWorking(Client, batches); } - [Fact] - public async Task DispatchingEventThroughJSInterop() - { - // Arrange - var (interopCalls, dotNetCompletions, batches) = ConfigureClient(); - await GoToTestComponent(batches); - var sink = _serverFixture.Host.Services.GetRequiredService(); - var logEvents = new List<(LogLevel logLevel, string eventIdName)>(); - sink.MessageLogged += (wc) => logEvents.Add((wc.LogLevel, wc.EventId.Name)); - - // Act - var mouseEventArgs = new UIMouseEventArgs() - { - Type = "click", - Detail = 1 - }; - var browserDescriptor = new RendererRegistryEventDispatcher.BrowserEventDescriptor() - { - BrowserRendererId = 0, - EventHandlerId = 1, - EventArgsType = "mouse", - }; - - var serializerOptions = TestJsonSerializerOptionsProvider.Options; - var uiArgs = JsonSerializer.Serialize(mouseEventArgs, serializerOptions); - - await Assert.ThrowsAsync(() => Client.InvokeDotNetMethod( - 0, - "Microsoft.AspNetCore.Components.Web", - "DispatchEvent", - null, - JsonSerializer.Serialize(new object[] { browserDescriptor, uiArgs }, serializerOptions))); - - Assert.Contains( - (LogLevel.Debug, "DispatchEventThroughJSInterop"), - logEvents); - - await ValidateClientKeepsWorking(Client, batches); - } - - [Fact] public async Task EventHandlerThrowsSyncExceptionTerminatesTheCircuit() { @@ -519,7 +501,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests "Handler threw an exception" == e.exception.Message); } - private Task ValidateClientKeepsWorking(BlazorClient Client, List<(int, int, byte[])> batches) => + private Task ValidateClientKeepsWorking(BlazorClient Client, List<(int, byte[])> batches) => ValidateClientKeepsWorking(Client, () => batches.Count); private async Task ValidateClientKeepsWorking(BlazorClient Client, Func countAccessor) @@ -530,7 +512,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests Assert.Equal(currentBatches + 1, countAccessor()); } - private async Task GoToTestComponent(List<(int, int, byte[])> batches) + private async Task GoToTestComponent(List<(int, byte[])> batches) { var rootUri = _serverFixture.RootUri; Assert.True(await Client.ConnectAsync(new Uri(rootUri, "/subdir"), prerendered: false), "Couldn't connect to the app"); @@ -540,12 +522,12 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests Assert.Equal(2, batches.Count); } - private (List<(int id, string identifier, string args)>, List, List<(int, int, byte[])>) ConfigureClient() + private (List<(int id, string identifier, string args)>, List, List<(int, byte[])>) ConfigureClient() { var interopCalls = new List<(int, string, string)>(); Client.JSInterop += (int arg1, string arg2, string arg3) => interopCalls.Add((arg1, arg2, arg3)); - var batches = new List<(int, int, byte[])>(); - Client.RenderBatchReceived += (id, renderer, data) => batches.Add((id, renderer, data)); + var batches = new List<(int, byte[])>(); + Client.RenderBatchReceived += (renderer, data) => batches.Add((renderer, data)); var endInvokeDotNetCompletions = new List(); Client.DotNetInteropCompletion += (completion) => endInvokeDotNetCompletions.Add(completion); return (interopCalls, endInvokeDotNetCompletions, batches); diff --git a/src/Components/test/E2ETest/ServerExecutionTests/RemoteRendererBufferLimitTest.cs b/src/Components/test/E2ETest/ServerExecutionTests/RemoteRendererBufferLimitTest.cs index 7377b28a9d..3ff526ce2d 100644 --- a/src/Components/test/E2ETest/ServerExecutionTests/RemoteRendererBufferLimitTest.cs +++ b/src/Components/test/E2ETest/ServerExecutionTests/RemoteRendererBufferLimitTest.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests _ = _serverFixture.RootUri; Client = new BlazorClient() { DefaultLatencyTimeout = DefaultLatencyTimeout }; - Client.RenderBatchReceived += (rendererId, id, data) => Batches.Add(new Batch(rendererId, id, data)); + Client.RenderBatchReceived += (id, data) => Batches.Add(new Batch(id, data)); Sink = _serverFixture.Host.Services.GetRequiredService(); Sink.MessageLogged += LogMessages; @@ -101,15 +101,13 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests private class Batch { - public Batch(int rendererId, int id, byte[] data) + public Batch(int id, byte[] data) { Id = id; - RendererId = rendererId; Data = data; } public int Id { get; } - public int RendererId { get; } public byte[] Data { get; } } diff --git a/src/Components/test/testassets/Ignitor/BlazorClient.cs b/src/Components/test/testassets/Ignitor/BlazorClient.cs index fa28c7f1b9..e6867ef73b 100644 --- a/src/Components/test/testassets/Ignitor/BlazorClient.cs +++ b/src/Components/test/testassets/Ignitor/BlazorClient.cs @@ -50,7 +50,7 @@ namespace Ignitor public event Action JSInterop; - public event Action RenderBatchReceived; + public event Action RenderBatchReceived; public event Action DotNetInteropCompletion; @@ -232,7 +232,7 @@ namespace Ignitor HubConnection.On("JS.BeginInvokeJS", OnBeginInvokeJS); HubConnection.On("JS.EndInvokeDotNet", OnEndInvokeDotNet); - HubConnection.On("JS.RenderBatch", OnRenderBatch); + HubConnection.On("JS.RenderBatch", OnRenderBatch); HubConnection.On("JS.Error", OnError); HubConnection.Closed += OnClosedAsync; @@ -286,11 +286,11 @@ namespace Ignitor } } - private void OnRenderBatch(int browserRendererId, int batchId, byte[] batchData) + private void OnRenderBatch(int batchId, byte[] batchData) { try { - RenderBatchReceived?.Invoke(browserRendererId, batchId, batchData); + RenderBatchReceived?.Invoke(batchId, batchData); var batch = RenderBatchReader.Read(batchData); diff --git a/src/Components/test/testassets/Ignitor/ElementNode.cs b/src/Components/test/testassets/Ignitor/ElementNode.cs index 2bb447d127..527f4b30c5 100644 --- a/src/Components/test/testassets/Ignitor/ElementNode.cs +++ b/src/Components/test/testassets/Ignitor/ElementNode.cs @@ -75,7 +75,7 @@ namespace Ignitor Value = value }; - var browserDescriptor = new RendererRegistryEventDispatcher.BrowserEventDescriptor() + var webEventDescriptor = new WebEventDescriptor() { BrowserRendererId = 0, EventHandlerId = changeEventDescriptor.EventId, @@ -87,7 +87,7 @@ namespace Ignitor } }; - return DispatchEventCore(connection, Serialize(browserDescriptor), Serialize(args)); + return DispatchEventCore(connection, Serialize(webEventDescriptor), Serialize(args)); } public Task ClickAsync(HubConnection connection) @@ -102,14 +102,14 @@ namespace Ignitor Type = clickEventDescriptor.EventName, Detail = 1 }; - var browserDescriptor = new RendererRegistryEventDispatcher.BrowserEventDescriptor() + var webEventDescriptor = new WebEventDescriptor { BrowserRendererId = 0, EventHandlerId = clickEventDescriptor.EventId, EventArgsType = "mouse", }; - return DispatchEventCore(connection, Serialize(browserDescriptor), Serialize(mouseEventArgs)); + return DispatchEventCore(connection, Serialize(webEventDescriptor), Serialize(mouseEventArgs)); } private static string Serialize(T payload) => diff --git a/src/Components/test/testassets/Ignitor/Program.cs b/src/Components/test/testassets/Ignitor/Program.cs index 372ee5a56c..8d7d60d663 100644 --- a/src/Components/test/testassets/Ignitor/Program.cs +++ b/src/Components/test/testassets/Ignitor/Program.cs @@ -38,7 +38,7 @@ namespace Ignitor var done = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); // Click the counter button 1000 times - client.RenderBatchReceived += (int browserRendererId, int batchId, byte[] data) => + client.RenderBatchReceived += (int batchId, byte[] data) => { if (batchId < 1000) { diff --git a/src/Identity/UI/src/Microsoft.AspNetCore.Identity.UI.csproj b/src/Identity/UI/src/Microsoft.AspNetCore.Identity.UI.csproj index 7fe773e2c6..3b2154e8f1 100644 --- a/src/Identity/UI/src/Microsoft.AspNetCore.Identity.UI.csproj +++ b/src/Identity/UI/src/Microsoft.AspNetCore.Identity.UI.csproj @@ -30,6 +30,8 @@ + + diff --git a/src/Identity/UI/src/build/Microsoft.AspnetCore.Identity.UI.targets b/src/Identity/UI/src/build/Microsoft.AspnetCore.Identity.UI.targets new file mode 100644 index 0000000000..b4238e7266 --- /dev/null +++ b/src/Identity/UI/src/build/Microsoft.AspnetCore.Identity.UI.targets @@ -0,0 +1,34 @@ + + + + + + <_IdentityUIBootstrap3WarningMessage>'Bootstrap3' is obsolete. It is recommended that the application is updated to use a supported Bootstrap version by removing the 'IdentityUIFrameworkVersion' property from '$(MSBuildProjectFile)' or setting 'IdentityUIFrameworkVersion' explicitly to 'Bootstrap4'. + + <_IdentityUIUnknownVersionErrorMessage>The 'IdentityUIFrameworkVersion' '$(IdentityUIFrameworkVersion)' in '$(MSBuildProjectFile)' is not valid. Valid versions are 'Bootstrap3' and 'Bootstrap4'. + + + + + <_IdentityUIActiveWarnings Include="IdentityUI001;IdentityUI002" Exclude="$(NoWarn)" /> + + + + + + + + + + + diff --git a/src/Identity/UI/src/buildMultiTargeting/Microsoft.AspnetCore.Identity.UI.targets b/src/Identity/UI/src/buildMultiTargeting/Microsoft.AspnetCore.Identity.UI.targets new file mode 100644 index 0000000000..fa5f1cabe2 --- /dev/null +++ b/src/Identity/UI/src/buildMultiTargeting/Microsoft.AspnetCore.Identity.UI.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Identity/UI/src/buildTransitive/Microsoft.AspnetCore.Identity.UI.targets b/src/Identity/UI/src/buildTransitive/Microsoft.AspnetCore.Identity.UI.targets new file mode 100644 index 0000000000..52d91a14f5 --- /dev/null +++ b/src/Identity/UI/src/buildTransitive/Microsoft.AspnetCore.Identity.UI.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Middleware/Middleware.sln b/src/Middleware/Middleware.sln index f62cfabeb6..f29cf549fd 100644 --- a/src/Middleware/Middleware.sln +++ b/src/Middleware/Middleware.sln @@ -255,8 +255,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.NodeSe EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SpaServices", "SpaServices", "{D6FA4ABE-E685-4EDD-8B06-D8777E76B472}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Webpack", "SpaServices\samples\Webpack\Webpack.csproj", "{121DFA13-E965-4C91-A175-19EF20DFD5AC}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SpaServices", "SpaServices\src\Microsoft.AspNetCore.SpaServices.csproj", "{D9D02772-1D53-45C3-B2CC-888F9978958C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SpaServices.Extensions", "SpaServices.Extensions\src\Microsoft.AspNetCore.SpaServices.Extensions.csproj", "{5D5B7E54-9323-498A-8983-E9BDFA3B2D07}" @@ -297,6 +295,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestOrigin", "CORS\test\tes EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore", "..\DefaultBuilder\src\Microsoft.AspNetCore.csproj", "{46B4FE62-06A1-4D54-B3E8-D8B4B3560075}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IntegrationTesting.IIS", "..\Servers\IIS\IntegrationTesting.IIS\src\Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj", "{92E11EBB-759E-4DA8-AB61-A9977D9F97D0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.SpaServices.Extensions.Tests", "SpaServices.Extensions\test\Microsoft.AspNetCore.SpaServices.Extensions.Tests.csproj", "{D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1423,18 +1425,6 @@ Global {40951683-DBC4-437A-BBAB-2FA7147E11EA}.Release|x64.Build.0 = Release|Any CPU {40951683-DBC4-437A-BBAB-2FA7147E11EA}.Release|x86.ActiveCfg = Release|Any CPU {40951683-DBC4-437A-BBAB-2FA7147E11EA}.Release|x86.Build.0 = Release|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Debug|x64.ActiveCfg = Debug|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Debug|x64.Build.0 = Debug|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Debug|x86.ActiveCfg = Debug|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Debug|x86.Build.0 = Debug|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Release|Any CPU.Build.0 = Release|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Release|x64.ActiveCfg = Release|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Release|x64.Build.0 = Release|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Release|x86.ActiveCfg = Release|Any CPU - {121DFA13-E965-4C91-A175-19EF20DFD5AC}.Release|x86.Build.0 = Release|Any CPU {D9D02772-1D53-45C3-B2CC-888F9978958C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D9D02772-1D53-45C3-B2CC-888F9978958C}.Debug|Any CPU.Build.0 = Debug|Any CPU {D9D02772-1D53-45C3-B2CC-888F9978958C}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -1627,6 +1617,30 @@ Global {46B4FE62-06A1-4D54-B3E8-D8B4B3560075}.Release|x64.Build.0 = Release|Any CPU {46B4FE62-06A1-4D54-B3E8-D8B4B3560075}.Release|x86.ActiveCfg = Release|Any CPU {46B4FE62-06A1-4D54-B3E8-D8B4B3560075}.Release|x86.Build.0 = Release|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Debug|x64.ActiveCfg = Debug|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Debug|x64.Build.0 = Debug|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Debug|x86.ActiveCfg = Debug|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Debug|x86.Build.0 = Debug|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Release|Any CPU.Build.0 = Release|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Release|x64.ActiveCfg = Release|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Release|x64.Build.0 = Release|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Release|x86.ActiveCfg = Release|Any CPU + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0}.Release|x86.Build.0 = Release|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Debug|x64.ActiveCfg = Debug|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Debug|x64.Build.0 = Debug|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Debug|x86.ActiveCfg = Debug|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Debug|x86.Build.0 = Debug|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Release|Any CPU.Build.0 = Release|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Release|x64.ActiveCfg = Release|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Release|x64.Build.0 = Release|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Release|x86.ActiveCfg = Release|Any CPU + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1736,7 +1750,6 @@ Global {47B6636D-09A3-47AE-9303-9F5D15EEE9D8} = {ACA6DDB9-7592-47CE-A740-D15BF307E9E0} {C801B6A3-906F-406F-BA25-EAE0B4BCE5C9} = {17B409B3-7EC6-49D8-847E-CFAA319E01B5} {40951683-DBC4-437A-BBAB-2FA7147E11EA} = {17B409B3-7EC6-49D8-847E-CFAA319E01B5} - {121DFA13-E965-4C91-A175-19EF20DFD5AC} = {D6FA4ABE-E685-4EDD-8B06-D8777E76B472} {D9D02772-1D53-45C3-B2CC-888F9978958C} = {D6FA4ABE-E685-4EDD-8B06-D8777E76B472} {5D5B7E54-9323-498A-8983-E9BDFA3B2D07} = {D6FA4ABE-E685-4EDD-8B06-D8777E76B472} {B04E9CB6-0D1C-4C21-B626-89B6926A491F} = {17B409B3-7EC6-49D8-847E-CFAA319E01B5} @@ -1755,6 +1768,8 @@ Global {DFEB537A-2D35-4C62-8A13-42798DF66A80} = {BD7B3AD8-0BA6-405F-8CF6-24B9464D4B5B} {E0521105-3A7B-480B-B962-0BFC2838D919} = {BD7B3AD8-0BA6-405F-8CF6-24B9464D4B5B} {46B4FE62-06A1-4D54-B3E8-D8B4B3560075} = {ACA6DDB9-7592-47CE-A740-D15BF307E9E0} + {92E11EBB-759E-4DA8-AB61-A9977D9F97D0} = {ACA6DDB9-7592-47CE-A740-D15BF307E9E0} + {D0CB733B-4CE8-4F6C-BBB9-548EA1A96966} = {D6FA4ABE-E685-4EDD-8B06-D8777E76B472} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {83786312-A93B-4BB4-AB06-7C6913A59AFA} diff --git a/src/Middleware/NodeServices/ref/Microsoft.AspNetCore.NodeServices.netcoreapp3.0.cs b/src/Middleware/NodeServices/ref/Microsoft.AspNetCore.NodeServices.netcoreapp3.0.cs index 659d4eb1f2..c57f1991df 100644 --- a/src/Middleware/NodeServices/ref/Microsoft.AspNetCore.NodeServices.netcoreapp3.0.cs +++ b/src/Middleware/NodeServices/ref/Microsoft.AspNetCore.NodeServices.netcoreapp3.0.cs @@ -3,10 +3,13 @@ namespace Microsoft.AspNetCore.NodeServices { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static partial class EmbeddedResourceReader { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static string Read(System.Type assemblyContainingType, string path) { throw null; } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial interface INodeServices : System.IDisposable { System.Threading.Tasks.Task InvokeAsync(string moduleName, params object[] args); @@ -14,10 +17,13 @@ namespace Microsoft.AspNetCore.NodeServices System.Threading.Tasks.Task InvokeExportAsync(string moduleName, string exportedFunctionName, params object[] args); System.Threading.Tasks.Task InvokeExportAsync(System.Threading.CancellationToken cancellationToken, string moduleName, string exportedFunctionName, params object[] args); } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static partial class NodeServicesFactory { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static Microsoft.AspNetCore.NodeServices.INodeServices CreateNodeServices(Microsoft.AspNetCore.NodeServices.NodeServicesOptions options) { throw null; } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial class NodeServicesOptions { public NodeServicesOptions(System.IServiceProvider serviceProvider) { } @@ -31,6 +37,7 @@ namespace Microsoft.AspNetCore.NodeServices public string ProjectPath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public string[] WatchFileExtensions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public sealed partial class StringAsTempFile : System.IDisposable { public StringAsTempFile(string content, System.Threading.CancellationToken applicationStoppingToken) { } @@ -41,10 +48,12 @@ namespace Microsoft.AspNetCore.NodeServices } namespace Microsoft.AspNetCore.NodeServices.HostingModels { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial interface INodeInstance : System.IDisposable { System.Threading.Tasks.Task InvokeExportAsync(System.Threading.CancellationToken cancellationToken, string moduleName, string exportNameOrNull, params object[] args); } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial class NodeInvocationException : System.Exception { public NodeInvocationException(string message, string details) { } @@ -52,6 +61,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels public bool AllowConnectionDraining { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } public bool NodeInstanceUnavailable { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial class NodeInvocationInfo { public NodeInvocationInfo() { } @@ -59,10 +69,13 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels public string ExportedFunctionName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public string ModuleName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static partial class NodeServicesOptionsExtensions { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void UseHttpHosting(this Microsoft.AspNetCore.NodeServices.NodeServicesOptions options) { } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public abstract partial class OutOfProcessNodeInstance : Microsoft.AspNetCore.NodeServices.HostingModels.INodeInstance, System.IDisposable { protected readonly Microsoft.Extensions.Logging.ILogger OutputLogger; @@ -80,9 +93,12 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels } namespace Microsoft.Extensions.DependencyInjection { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static partial class NodeServicesServiceCollectionExtensions { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void AddNodeServices(this Microsoft.Extensions.DependencyInjection.IServiceCollection serviceCollection) { } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void AddNodeServices(this Microsoft.Extensions.DependencyInjection.IServiceCollection serviceCollection, System.Action setupAction) { } } } diff --git a/src/Middleware/NodeServices/samples/NodeServicesExamples/Controllers/HomeController.cs b/src/Middleware/NodeServices/samples/NodeServicesExamples/Controllers/HomeController.cs index d9f32410eb..b6cf86a9bd 100644 --- a/src/Middleware/NodeServices/samples/NodeServicesExamples/Controllers/HomeController.cs +++ b/src/Middleware/NodeServices/samples/NodeServicesExamples/Controllers/HomeController.cs @@ -1,7 +1,9 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.NodeServices; -using Microsoft.AspNetCore.SpaServices.Prerendering; namespace NodeServicesExamples.Controllers { @@ -17,7 +19,9 @@ namespace NodeServicesExamples.Controllers return View(); } +#pragma warning disable 0618 public async Task Chart([FromServices] INodeServices nodeServices) +#pragma warning restore 0618 { var options = new { width = 400, height = 200, showArea = true, showPoint = true, fullWidth = true }; var data = new @@ -35,20 +39,6 @@ namespace NodeServicesExamples.Controllers return View(); } - public async Task Prerendering([FromServices] ISpaPrerenderer prerenderer) - { - var result = await prerenderer.RenderToString("./Node/prerenderPage"); - - if (!string.IsNullOrEmpty(result.RedirectUrl)) - { - return Redirect(result.RedirectUrl); - } - - ViewData["PrerenderedHtml"] = result.Html; - ViewData["PrerenderedGlobals"] = result.CreateGlobalsAssignmentScript(); - return View(); - } - public IActionResult Error() { return View("~/Views/Shared/Error.cshtml"); diff --git a/src/Middleware/NodeServices/samples/NodeServicesExamples/NodeServicesExamples.csproj b/src/Middleware/NodeServices/samples/NodeServicesExamples/NodeServicesExamples.csproj index d5bea12a23..13ae55cac3 100644 --- a/src/Middleware/NodeServices/samples/NodeServicesExamples/NodeServicesExamples.csproj +++ b/src/Middleware/NodeServices/samples/NodeServicesExamples/NodeServicesExamples.csproj @@ -7,14 +7,15 @@ - - + + + diff --git a/src/Middleware/NodeServices/samples/NodeServicesExamples/Startup.cs b/src/Middleware/NodeServices/samples/NodeServicesExamples/Startup.cs index 585d6f30ef..60cb8044e1 100644 --- a/src/Middleware/NodeServices/samples/NodeServicesExamples/Startup.cs +++ b/src/Middleware/NodeServices/samples/NodeServicesExamples/Startup.cs @@ -1,15 +1,20 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.NodeServices; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using System.IO; namespace NodeServicesExamples { public class Startup { +#pragma warning disable 0618 // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { @@ -17,7 +22,6 @@ namespace NodeServicesExamples // Enable Node Services services.AddNodeServices(); - services.AddSpaPrerenderer(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -26,11 +30,14 @@ namespace NodeServicesExamples app.UseDeveloperExceptionPage(); // Dynamically transpile any .js files under the '/js/' directory - app.Use(next => async context => { + app.Use(next => async context => + { var requestPath = context.Request.Path.Value; - if (requestPath.StartsWith("/js/") && requestPath.EndsWith(".js")) { + if (requestPath.StartsWith("/js/") && requestPath.EndsWith(".js")) + { var fileInfo = env.WebRootFileProvider.GetFileInfo(requestPath); - if (fileInfo.Exists) { + if (fileInfo.Exists) + { var transpiled = await nodeServices.InvokeAsync("./Node/transpilation.js", fileInfo.PhysicalPath, requestPath); await context.Response.WriteAsync(transpiled); return; @@ -49,6 +56,7 @@ namespace NodeServicesExamples endpoints.MapDefaultControllerRoute(); }); } +#pragma warning restore 0618 public static void Main(string[] args) { diff --git a/src/Middleware/NodeServices/src/Configuration/NodeServicesFactory.cs b/src/Middleware/NodeServices/src/Configuration/NodeServicesFactory.cs index 8432158cb9..06968643bd 100644 --- a/src/Middleware/NodeServices/src/Configuration/NodeServicesFactory.cs +++ b/src/Middleware/NodeServices/src/Configuration/NodeServicesFactory.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; namespace Microsoft.AspNetCore.NodeServices @@ -5,6 +8,7 @@ namespace Microsoft.AspNetCore.NodeServices /// /// Supplies INodeServices instances. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static class NodeServicesFactory { /// @@ -12,6 +16,7 @@ namespace Microsoft.AspNetCore.NodeServices /// /// Options for creating the instance. /// An instance. + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static INodeServices CreateNodeServices(NodeServicesOptions options) { if (options == null) @@ -22,4 +27,4 @@ namespace Microsoft.AspNetCore.NodeServices return new NodeServicesImpl(options.NodeInstanceFactory); } } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/Configuration/NodeServicesOptions.cs b/src/Middleware/NodeServices/src/Configuration/NodeServicesOptions.cs index 4d8d2e6a2b..a7aac6eba4 100644 --- a/src/Middleware/NodeServices/src/Configuration/NodeServicesOptions.cs +++ b/src/Middleware/NodeServices/src/Configuration/NodeServicesOptions.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Collections.Generic; using System.IO; @@ -14,6 +17,7 @@ namespace Microsoft.AspNetCore.NodeServices /// /// Describes options used to configure an instance. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public class NodeServicesOptions { internal const string TimeoutConfigPropertyName = nameof(InvocationTimeoutMilliseconds); diff --git a/src/Middleware/NodeServices/src/Configuration/NodeServicesServiceCollectionExtensions.cs b/src/Middleware/NodeServices/src/Configuration/NodeServicesServiceCollectionExtensions.cs index f74ae0889c..1d793671b8 100644 --- a/src/Middleware/NodeServices/src/Configuration/NodeServicesServiceCollectionExtensions.cs +++ b/src/Middleware/NodeServices/src/Configuration/NodeServicesServiceCollectionExtensions.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using Microsoft.AspNetCore.NodeServices; @@ -6,12 +9,14 @@ namespace Microsoft.Extensions.DependencyInjection /// /// Extension methods for setting up NodeServices in an . /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static class NodeServicesServiceCollectionExtensions { /// /// Adds NodeServices support to the . /// /// The . + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void AddNodeServices(this IServiceCollection serviceCollection) => AddNodeServices(serviceCollection, _ => {}); @@ -20,6 +25,7 @@ namespace Microsoft.Extensions.DependencyInjection /// /// The . /// A callback that will be invoked to populate the . + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void AddNodeServices(this IServiceCollection serviceCollection, Action setupAction) { if (setupAction == null) diff --git a/src/Middleware/NodeServices/src/HostingModels/HttpNodeInstance.cs b/src/Middleware/NodeServices/src/HostingModels/HttpNodeInstance.cs index 1466db3eaf..9d7f5726b2 100644 --- a/src/Middleware/NodeServices/src/HostingModels/HttpNodeInstance.cs +++ b/src/Middleware/NodeServices/src/HostingModels/HttpNodeInstance.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.IO; using System.Net.Http; @@ -19,6 +22,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels /// accept RPC invocations. /// /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] internal class HttpNodeInstance : OutOfProcessNodeInstance { private static readonly Regex EndpointMessageRegex = diff --git a/src/Middleware/NodeServices/src/HostingModels/INodeInstance.cs b/src/Middleware/NodeServices/src/HostingModels/INodeInstance.cs index a1ce02146a..00bc1277ba 100644 --- a/src/Middleware/NodeServices/src/HostingModels/INodeInstance.cs +++ b/src/Middleware/NodeServices/src/HostingModels/INodeInstance.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Threading; using System.Threading.Tasks; @@ -7,6 +10,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels /// /// Represents an instance of Node.js to which Remote Procedure Calls (RPC) may be sent. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public interface INodeInstance : IDisposable { /// @@ -20,4 +24,4 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels /// A representing the completion of the RPC call. Task InvokeExportAsync(CancellationToken cancellationToken, string moduleName, string exportNameOrNull, params object[] args); } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/HostingModels/NodeInvocationException.cs b/src/Middleware/NodeServices/src/HostingModels/NodeInvocationException.cs index dea3c2cc7e..6e4b97b4be 100644 --- a/src/Middleware/NodeServices/src/HostingModels/NodeInvocationException.cs +++ b/src/Middleware/NodeServices/src/HostingModels/NodeInvocationException.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; namespace Microsoft.AspNetCore.NodeServices.HostingModels @@ -5,6 +8,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels /// /// Represents an exception caused by invoking Node.js code. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public class NodeInvocationException : Exception { /// @@ -52,4 +56,4 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels AllowConnectionDraining = allowConnectionDraining; } } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/HostingModels/NodeInvocationInfo.cs b/src/Middleware/NodeServices/src/HostingModels/NodeInvocationInfo.cs index 86c427327b..7d32eacb26 100644 --- a/src/Middleware/NodeServices/src/HostingModels/NodeInvocationInfo.cs +++ b/src/Middleware/NodeServices/src/HostingModels/NodeInvocationInfo.cs @@ -1,8 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + namespace Microsoft.AspNetCore.NodeServices.HostingModels { /// /// Describes an RPC call sent from .NET code to Node.js code. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public class NodeInvocationInfo { /// diff --git a/src/Middleware/NodeServices/src/HostingModels/NodeServicesOptionsExtensions.cs b/src/Middleware/NodeServices/src/HostingModels/NodeServicesOptionsExtensions.cs index 2cbe0a0f1c..674f0ee6dc 100644 --- a/src/Middleware/NodeServices/src/HostingModels/NodeServicesOptionsExtensions.cs +++ b/src/Middleware/NodeServices/src/HostingModels/NodeServicesOptionsExtensions.cs @@ -1,17 +1,24 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + namespace Microsoft.AspNetCore.NodeServices.HostingModels { /// /// Extension methods that help with populating a object. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static class NodeServicesOptionsExtensions { /// /// Configures the service so that it will use out-of-process /// Node.js instances and perform RPC calls over HTTP. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void UseHttpHosting(this NodeServicesOptions options) { options.NodeInstanceFactory = () => new HttpNodeInstance(options); } } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/HostingModels/OutOfProcessNodeInstance.cs b/src/Middleware/NodeServices/src/HostingModels/OutOfProcessNodeInstance.cs index b75827c452..cf68baa338 100644 --- a/src/Middleware/NodeServices/src/HostingModels/OutOfProcessNodeInstance.cs +++ b/src/Middleware/NodeServices/src/HostingModels/OutOfProcessNodeInstance.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Collections.Generic; using System.Diagnostics; @@ -19,6 +22,7 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels /// protocol, or any other RPC-type mechanism). /// /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public abstract class OutOfProcessNodeInstance : INodeInstance { /// @@ -472,4 +476,4 @@ namespace Microsoft.AspNetCore.NodeServices.HostingModels Dispose(false); } } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/INodeServices.cs b/src/Middleware/NodeServices/src/INodeServices.cs index 2a1ce1aa77..a88ece3c5c 100644 --- a/src/Middleware/NodeServices/src/INodeServices.cs +++ b/src/Middleware/NodeServices/src/INodeServices.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Threading; using System.Threading.Tasks; @@ -9,6 +12,7 @@ namespace Microsoft.AspNetCore.NodeServices /// might change over time (e.g., the process might be restarted), the instance /// will remain constant. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public interface INodeServices : IDisposable { /// @@ -51,4 +55,4 @@ namespace Microsoft.AspNetCore.NodeServices /// A representing the completion of the RPC call. Task InvokeExportAsync(CancellationToken cancellationToken, string moduleName, string exportedFunctionName, params object[] args); } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/NodeServicesImpl.cs b/src/Middleware/NodeServices/src/NodeServicesImpl.cs index d1cf92404f..621a9af7cc 100644 --- a/src/Middleware/NodeServices/src/NodeServicesImpl.cs +++ b/src/Middleware/NodeServices/src/NodeServicesImpl.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Threading; using System.Threading.Tasks; @@ -17,6 +20,7 @@ namespace Microsoft.AspNetCore.NodeServices /// analogous to the "connection draining" feature implemented by HTTP load balancers. /// /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] internal class NodeServicesImpl : INodeServices { private static TimeSpan ConnectionDrainingTimespan = TimeSpan.FromSeconds(15); @@ -162,4 +166,4 @@ namespace Microsoft.AspNetCore.NodeServices return _nodeInstanceFactory(); } } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/Util/EmbeddedResourceReader.cs b/src/Middleware/NodeServices/src/Util/EmbeddedResourceReader.cs index 053182669b..0c4c777e74 100644 --- a/src/Middleware/NodeServices/src/Util/EmbeddedResourceReader.cs +++ b/src/Middleware/NodeServices/src/Util/EmbeddedResourceReader.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.IO; using System.Reflection; @@ -7,6 +10,7 @@ namespace Microsoft.AspNetCore.NodeServices /// /// Contains methods for reading embedded resources. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static class EmbeddedResourceReader { /// @@ -15,6 +19,7 @@ namespace Microsoft.AspNetCore.NodeServices /// Any in the assembly whose resource is to be read. /// The path of the resource to be read. /// The contents of the resource. + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static string Read(Type assemblyContainingType, string path) { var asm = assemblyContainingType.GetTypeInfo().Assembly; @@ -27,4 +32,4 @@ namespace Microsoft.AspNetCore.NodeServices } } } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/Util/StringAsTempFile.cs b/src/Middleware/NodeServices/src/Util/StringAsTempFile.cs index c4aea7ff2d..ed9ee76172 100644 --- a/src/Middleware/NodeServices/src/Util/StringAsTempFile.cs +++ b/src/Middleware/NodeServices/src/Util/StringAsTempFile.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.IO; using System.Threading; @@ -7,6 +10,7 @@ namespace Microsoft.AspNetCore.NodeServices /// /// Makes it easier to pass script files to Node in a way that's sure to clean up after the process exits. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public sealed class StringAsTempFile : IDisposable { private bool _disposedValue; @@ -79,4 +83,4 @@ namespace Microsoft.AspNetCore.NodeServices DisposeImpl(false); } } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/src/Util/TaskExtensions.cs b/src/Middleware/NodeServices/src/Util/TaskExtensions.cs index 75cfdb1604..8743b9e4b5 100644 --- a/src/Middleware/NodeServices/src/Util/TaskExtensions.cs +++ b/src/Middleware/NodeServices/src/Util/TaskExtensions.cs @@ -1,10 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.Threading; using System.Threading.Tasks; namespace Microsoft.AspNetCore.NodeServices { + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] internal static class TaskExtensions { + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static Task OrThrowOnCancellation(this Task task, CancellationToken cancellationToken) { return task.IsCompleted @@ -16,6 +22,7 @@ namespace Microsoft.AspNetCore.NodeServices TaskScheduler.Default); } + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static Task OrThrowOnCancellation(this Task task, CancellationToken cancellationToken) { return task.IsCompleted @@ -27,4 +34,4 @@ namespace Microsoft.AspNetCore.NodeServices TaskScheduler.Default); } } -} \ No newline at end of file +} diff --git a/src/Middleware/NodeServices/test/NodeServicesTest.cs b/src/Middleware/NodeServices/test/NodeServicesTest.cs index f851e08d0c..2bae8f11b6 100644 --- a/src/Middleware/NodeServices/test/NodeServicesTest.cs +++ b/src/Middleware/NodeServices/test/NodeServicesTest.cs @@ -1,15 +1,16 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.NodeServices.HostingModels; -using Microsoft.Extensions.DependencyInjection; using System; using System.IO; using System.Threading.Tasks; +using Microsoft.AspNetCore.NodeServices.HostingModels; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.AspNetCore.NodeServices { + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public class NodeServicesTest : IDisposable { private readonly INodeServices _nodeServices; diff --git a/src/Middleware/SpaServices.Extensions/ref/Microsoft.AspNetCore.SpaServices.Extensions.netcoreapp3.0.cs b/src/Middleware/SpaServices.Extensions/ref/Microsoft.AspNetCore.SpaServices.Extensions.netcoreapp3.0.cs index 9dfedd1041..6691b79a64 100644 --- a/src/Middleware/SpaServices.Extensions/ref/Microsoft.AspNetCore.SpaServices.Extensions.netcoreapp3.0.cs +++ b/src/Middleware/SpaServices.Extensions/ref/Microsoft.AspNetCore.SpaServices.Extensions.netcoreapp3.0.cs @@ -7,10 +7,13 @@ namespace Microsoft.AspNetCore.Builder { public static void UseSpa(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, System.Action configuration) { } } + [System.ObsoleteAttribute("Prerendering is no longer supported out of box")] public static partial class SpaPrerenderingExtensions { + [System.ObsoleteAttribute("Prerendering is no longer supported out of box")] public static void UseSpaPrerendering(this Microsoft.AspNetCore.SpaServices.ISpaBuilder spaBuilder, System.Action configuration) { } } + [System.ObsoleteAttribute("Prerendering is no longer supported out of box")] public partial class SpaPrerenderingOptions { public SpaPrerenderingOptions() { } @@ -45,6 +48,7 @@ namespace Microsoft.AspNetCore.SpaServices } namespace Microsoft.AspNetCore.SpaServices.AngularCli { + [System.ObsoleteAttribute("Prerendering is no longer supported out of box")] public partial class AngularCliBuilder : Microsoft.AspNetCore.SpaServices.Prerendering.ISpaPrerendererBuilder { public AngularCliBuilder(string npmScript) { } @@ -58,6 +62,7 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli } namespace Microsoft.AspNetCore.SpaServices.Prerendering { + [System.ObsoleteAttribute("Prerendering is no longer supported out of box")] public partial interface ISpaPrerendererBuilder { System.Threading.Tasks.Task Build(Microsoft.AspNetCore.SpaServices.ISpaBuilder spaBuilder); diff --git a/src/Middleware/SpaServices.Extensions/src/AngularCli/AngularCliBuilder.cs b/src/Middleware/SpaServices.Extensions/src/AngularCli/AngularCliBuilder.cs index c78e194726..24f0ba430f 100644 --- a/src/Middleware/SpaServices.Extensions/src/AngularCli/AngularCliBuilder.cs +++ b/src/Middleware/SpaServices.Extensions/src/AngularCli/AngularCliBuilder.cs @@ -17,6 +17,7 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli /// Provides an implementation of that can build /// an Angular application by invoking the Angular CLI. /// + [Obsolete("Prerendering is no longer supported out of box")] public class AngularCliBuilder : ISpaPrerendererBuilder { private static TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(5); // This is a development-time only feature, so a very long timeout is fine diff --git a/src/Middleware/SpaServices.Extensions/src/Microsoft.AspNetCore.SpaServices.Extensions.csproj b/src/Middleware/SpaServices.Extensions/src/Microsoft.AspNetCore.SpaServices.Extensions.csproj index 02741c62dc..38e9a0e72c 100644 --- a/src/Middleware/SpaServices.Extensions/src/Microsoft.AspNetCore.SpaServices.Extensions.csproj +++ b/src/Middleware/SpaServices.Extensions/src/Microsoft.AspNetCore.SpaServices.Extensions.csproj @@ -1,4 +1,4 @@ - + Helpers for building single-page applications on ASP.NET MVC Core. @@ -13,4 +13,8 @@ + + + + diff --git a/src/Middleware/SpaServices.Extensions/src/Prerendering/ISpaPrerendererBuilder.cs b/src/Middleware/SpaServices.Extensions/src/Prerendering/ISpaPrerendererBuilder.cs index 9c3171de87..4f98a0461a 100644 --- a/src/Middleware/SpaServices.Extensions/src/Prerendering/ISpaPrerendererBuilder.cs +++ b/src/Middleware/SpaServices.Extensions/src/Prerendering/ISpaPrerendererBuilder.cs @@ -1,7 +1,7 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Builder; +using System; using System.Threading.Tasks; namespace Microsoft.AspNetCore.SpaServices.Prerendering @@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// so that it can be prerendered. This is only intended to be used at development /// time. In production, a SPA should already have been built during publishing. /// + [Obsolete("Prerendering is no longer supported out of box")] public interface ISpaPrerendererBuilder { /// diff --git a/src/Middleware/SpaServices.Extensions/src/Prerendering/SpaPrerenderingExtensions.cs b/src/Middleware/SpaServices.Extensions/src/Prerendering/SpaPrerenderingExtensions.cs index 3b817494d7..a9438b3f4c 100644 --- a/src/Middleware/SpaServices.Extensions/src/Prerendering/SpaPrerenderingExtensions.cs +++ b/src/Middleware/SpaServices.Extensions/src/Prerendering/SpaPrerenderingExtensions.cs @@ -23,6 +23,7 @@ namespace Microsoft.AspNetCore.Builder /// /// Extension methods for configuring prerendering of a Single Page Application. /// + [Obsolete("Prerendering is no longer supported out of box")] public static class SpaPrerenderingExtensions { /// @@ -30,6 +31,7 @@ namespace Microsoft.AspNetCore.Builder /// /// The . /// Supplies configuration for the prerendering middleware. + [Obsolete("Prerendering is no longer supported out of box")] public static void UseSpaPrerendering( this ISpaBuilder spaBuilder, Action configuration) diff --git a/src/Middleware/SpaServices.Extensions/src/Prerendering/SpaPrerenderingOptions.cs b/src/Middleware/SpaServices.Extensions/src/Prerendering/SpaPrerenderingOptions.cs index bc121bbc9a..907bf066dd 100644 --- a/src/Middleware/SpaServices.Extensions/src/Prerendering/SpaPrerenderingOptions.cs +++ b/src/Middleware/SpaServices.Extensions/src/Prerendering/SpaPrerenderingOptions.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Http; @@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.Builder /// /// Represents options for the SPA prerendering middleware. /// + [Obsolete("Prerendering is no longer supported out of box")] public class SpaPrerenderingOptions { /// diff --git a/src/Middleware/SpaServices.Extensions/test/Microsoft.AspNetCore.SpaServices.Extensions.Tests.csproj b/src/Middleware/SpaServices.Extensions/test/Microsoft.AspNetCore.SpaServices.Extensions.Tests.csproj new file mode 100644 index 0000000000..78dc7705ba --- /dev/null +++ b/src/Middleware/SpaServices.Extensions/test/Microsoft.AspNetCore.SpaServices.Extensions.Tests.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp3.0 + true + + + + + + + + + + + + diff --git a/src/Middleware/SpaServices.Extensions/test/SpaServicesExtensionsTests.cs b/src/Middleware/SpaServices.Extensions/test/SpaServicesExtensionsTests.cs new file mode 100644 index 0000000000..8d55dc3f35 --- /dev/null +++ b/src/Middleware/SpaServices.Extensions/test/SpaServicesExtensionsTests.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.SpaServices.Extensions.Tests +{ + public class SpaServicesExtensionsTests + { + [Fact] + public void UseSpa_ThrowsInvalidOperationException_IfRootpathNotSet() + { + // Arrange + var applicationbuilder = GetApplicationBuilder(GetServiceProvider()); + + // Act & Assert + var exception = Assert.Throws( + () => applicationbuilder.UseSpa(rb => { })); + + Assert.Equal("No RootPath was set on the SpaStaticFilesOptions.", exception.Message); + } + + private IApplicationBuilder GetApplicationBuilder(IServiceProvider serviceProvider = null) + { + if(serviceProvider == null) + { + serviceProvider = new Mock(MockBehavior.Strict).Object; + } + + var applicationbuilderMock = new Mock(); + applicationbuilderMock + .Setup(s => s.ApplicationServices) + .Returns(serviceProvider); + + return applicationbuilderMock.Object; + } + + private IServiceProvider GetServiceProvider() + { + var services = new ServiceCollection(); + services.AddLogging(); + services.AddSpaStaticFiles(); + + return services.BuildServiceProvider(); + } + } +} diff --git a/src/Middleware/SpaServices/ref/Microsoft.AspNetCore.SpaServices.netcoreapp3.0.cs b/src/Middleware/SpaServices/ref/Microsoft.AspNetCore.SpaServices.netcoreapp3.0.cs index 9548d1f7b7..1b9fa3ae00 100644 --- a/src/Middleware/SpaServices/ref/Microsoft.AspNetCore.SpaServices.netcoreapp3.0.cs +++ b/src/Middleware/SpaServices/ref/Microsoft.AspNetCore.SpaServices.netcoreapp3.0.cs @@ -3,33 +3,41 @@ namespace Microsoft.AspNetCore.Builder { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static partial class SpaRouteExtensions { public static void MapSpaFallbackRoute(this Microsoft.AspNetCore.Routing.IRouteBuilder routeBuilder, string name, object defaults, object constraints = null, object dataTokens = null) { } public static void MapSpaFallbackRoute(this Microsoft.AspNetCore.Routing.IRouteBuilder routeBuilder, string name, string templatePrefix, object defaults, object constraints = null, object dataTokens = null) { } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static partial class WebpackDevMiddleware { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void UseWebpackDevMiddleware(this Microsoft.AspNetCore.Builder.IApplicationBuilder appBuilder, Microsoft.AspNetCore.SpaServices.Webpack.WebpackDevMiddlewareOptions options = null) { } } } namespace Microsoft.AspNetCore.SpaServices.Prerendering { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial interface ISpaPrerenderer { System.Threading.Tasks.Task RenderToString(string moduleName, string exportName = null, object customDataParameter = null, int timeoutMilliseconds = 0); } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial class JavaScriptModuleExport { public JavaScriptModuleExport(string moduleName) { } public string ExportName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public string ModuleName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static partial class Prerenderer { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static System.Threading.Tasks.Task RenderToString(string applicationBasePath, Microsoft.AspNetCore.NodeServices.INodeServices nodeServices, System.Threading.CancellationToken applicationStoppingToken, Microsoft.AspNetCore.SpaServices.Prerendering.JavaScriptModuleExport bootModule, string requestAbsoluteUrl, string requestPathAndQuery, object customDataParameter, int timeoutMilliseconds, string requestPathBase) { throw null; } } [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(Attributes="asp-prerender-module")] + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial class PrerenderTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper { public PrerenderTagHelper(System.IServiceProvider serviceProvider) { } @@ -47,6 +55,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering [System.Diagnostics.DebuggerStepThroughAttribute] public override System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output) { throw null; } } + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial class RenderToStringResult { public RenderToStringResult() { } @@ -59,6 +68,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering } namespace Microsoft.AspNetCore.SpaServices.Webpack { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public partial class WebpackDevMiddlewareOptions { public WebpackDevMiddlewareOptions() { } @@ -75,8 +85,10 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack } namespace Microsoft.Extensions.DependencyInjection { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static partial class PrerenderingServiceCollectionExtensions { + [System.ObsoleteAttribute("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void AddSpaPrerenderer(this Microsoft.Extensions.DependencyInjection.IServiceCollection serviceCollection) { } } } diff --git a/src/Middleware/SpaServices/samples/Webpack/.gitignore b/src/Middleware/SpaServices/samples/Webpack/.gitignore deleted file mode 100644 index 1363491964..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/.gitignore +++ /dev/null @@ -1,233 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -yarn.lock -wwwroot/dist - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ diff --git a/src/Middleware/SpaServices/samples/Webpack/ActionResults/PrerenderResult.cs b/src/Middleware/SpaServices/samples/Webpack/ActionResults/PrerenderResult.cs deleted file mode 100644 index b44d761b01..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/ActionResults/PrerenderResult.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.NodeServices; -using Microsoft.AspNetCore.SpaServices.Prerendering; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace Webpack.ActionResults -{ - // This is an example of how you could invoke the prerendering API from an ActionResult, so as to - // prerender a SPA component as the entire response page (instead of injecting the SPA component - // into a Razor view's output) - public class PrerenderResult : ActionResult - { - private JavaScriptModuleExport _moduleExport; - private object _dataToSupply; - - public PrerenderResult(JavaScriptModuleExport moduleExport, object dataToSupply = null) - { - _moduleExport = moduleExport; - _dataToSupply = dataToSupply; - } - - public override async Task ExecuteResultAsync(ActionContext context) - { - var nodeServices = context.HttpContext.RequestServices.GetRequiredService(); - var hostEnv = context.HttpContext.RequestServices.GetRequiredService(); - var applicationLifetime = context.HttpContext.RequestServices.GetRequiredService(); - var applicationBasePath = hostEnv.ContentRootPath; - var request = context.HttpContext.Request; - var response = context.HttpContext.Response; - - var prerenderedHtml = await Prerenderer.RenderToString( - applicationBasePath, - nodeServices, - applicationLifetime.ApplicationStopping, - _moduleExport, - request.GetEncodedUrl(), - request.Path + request.QueryString.Value, - _dataToSupply, - /* timeoutMilliseconds */ 30000, - /* requestPathBase */ "/" - ); - - response.ContentType = "text/html"; - await response.WriteAsync(prerenderedHtml.Html); - } - } -} diff --git a/src/Middleware/SpaServices/samples/Webpack/ActionResults/PrerenderResultExtensions.cs b/src/Middleware/SpaServices/samples/Webpack/ActionResults/PrerenderResultExtensions.cs deleted file mode 100644 index 926e114999..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/ActionResults/PrerenderResultExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.SpaServices.Prerendering; - -namespace Webpack.ActionResults -{ - public static class PrerenderResultExtensions - { - public static PrerenderResult Prerender(this ControllerBase controller, JavaScriptModuleExport exportToPrerender, object dataToSupply = null) - { - return new PrerenderResult(exportToPrerender, dataToSupply); - } - } -} diff --git a/src/Middleware/SpaServices/samples/Webpack/Clientside/App.ts b/src/Middleware/SpaServices/samples/Webpack/Clientside/App.ts deleted file mode 100644 index 07a4e7733f..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Clientside/App.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { HelloWorld } from './HelloWorld'; -import './styles/main.less'; - -new HelloWorld().doIt(); diff --git a/src/Middleware/SpaServices/samples/Webpack/Clientside/HelloWorld.ts b/src/Middleware/SpaServices/samples/Webpack/Clientside/HelloWorld.ts deleted file mode 100644 index 512dcf94c4..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Clientside/HelloWorld.ts +++ /dev/null @@ -1,5 +0,0 @@ -export class HelloWorld { - public doIt() { - console.log('Hello from MyApp'); - } -} diff --git a/src/Middleware/SpaServices/samples/Webpack/Clientside/styles/main.less b/src/Middleware/SpaServices/samples/Webpack/Clientside/styles/main.less deleted file mode 100644 index ea61843fc2..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Clientside/styles/main.less +++ /dev/null @@ -1,5 +0,0 @@ -@headerColor: red; - -h1 { - color: @headerColor; -} diff --git a/src/Middleware/SpaServices/samples/Webpack/Controllers/HomeController.cs b/src/Middleware/SpaServices/samples/Webpack/Controllers/HomeController.cs deleted file mode 100644 index 136e94e0a3..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Controllers/HomeController.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; - -namespace Webpack.Controllers -{ - public class HomeController : Controller - { - public IActionResult Index() - { - return View(); - } - } -} diff --git a/src/Middleware/SpaServices/samples/Webpack/Startup.cs b/src/Middleware/SpaServices/samples/Webpack/Startup.cs deleted file mode 100644 index 3aed2d5db4..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Startup.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.SpaServices.Webpack; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using System.IO; -using Microsoft.AspNetCore.NodeServices; - -namespace Webpack -{ - public class Startup - { - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddMvc(); - services.AddNodeServices(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app) - { - app.UseDeveloperExceptionPage(); - - // For real apps, you should only use Webpack Dev Middleware at development time. For production, - // you'll get better performance and reliability if you precompile the webpack output and simply - // serve the resulting static files. For examples of setting up this automatic switch between - // development-style and production-style webpack usage, see the 'templates' dir in this repo. - app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { - HotModuleReplacement = true - }); - - app.UseStaticFiles(); - app.UseRouting(); - app.UseEndpoints(endpoints => - { - endpoints.MapDefaultControllerRoute(); - }); - } - - public static void Main(string[] args) - { - var host = new WebHostBuilder() - .ConfigureLogging(factory => - { - factory.AddConsole(); - factory.AddDebug(); - }) - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseKestrel() - .UseStartup() - .Build(); - - host.Run(); - } - } -} diff --git a/src/Middleware/SpaServices/samples/Webpack/Views/Home/Index.cshtml b/src/Middleware/SpaServices/samples/Webpack/Views/Home/Index.cshtml deleted file mode 100644 index 7828ec195f..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Views/Home/Index.cshtml +++ /dev/null @@ -1,10 +0,0 @@ -@{ - ViewData["Title"] = "Home Page"; -} - -

Hello

-Hi there. Enter some text: - -@section scripts { - -} diff --git a/src/Middleware/SpaServices/samples/Webpack/Views/Shared/Error.cshtml b/src/Middleware/SpaServices/samples/Webpack/Views/Shared/Error.cshtml deleted file mode 100644 index 473b35d6ca..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Views/Shared/Error.cshtml +++ /dev/null @@ -1,6 +0,0 @@ -@{ - ViewData["Title"] = "Error"; -} - -

Error.

-

An error occurred while processing your request.

diff --git a/src/Middleware/SpaServices/samples/Webpack/Views/Shared/_Layout.cshtml b/src/Middleware/SpaServices/samples/Webpack/Views/Shared/_Layout.cshtml deleted file mode 100644 index 929671831e..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Views/Shared/_Layout.cshtml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - @ViewData["Title"] - - - - - - @RenderBody() - @RenderSection("scripts", required: false) - - diff --git a/src/Middleware/SpaServices/samples/Webpack/Views/_ViewImports.cshtml b/src/Middleware/SpaServices/samples/Webpack/Views/_ViewImports.cshtml deleted file mode 100644 index de3b5a18ab..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Views/_ViewImports.cshtml +++ /dev/null @@ -1,2 +0,0 @@ -@using Webpack -@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers" diff --git a/src/Middleware/SpaServices/samples/Webpack/Views/_ViewStart.cshtml b/src/Middleware/SpaServices/samples/Webpack/Views/_ViewStart.cshtml deleted file mode 100644 index 820a2f6e02..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Views/_ViewStart.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@{ - Layout = "_Layout"; -} diff --git a/src/Middleware/SpaServices/samples/Webpack/Webpack.csproj b/src/Middleware/SpaServices/samples/Webpack/Webpack.csproj deleted file mode 100644 index 494b84a780..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/Webpack.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - netcoreapp3.0 - true - false - - - - - - - - - - - - - - - - - - - diff --git a/src/Middleware/SpaServices/samples/Webpack/appsettings.json b/src/Middleware/SpaServices/samples/Webpack/appsettings.json deleted file mode 100644 index e5472e562b..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/appsettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Verbose", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/src/Middleware/SpaServices/samples/Webpack/package.json b/src/Middleware/SpaServices/samples/Webpack/package.json deleted file mode 100644 index 3216132bb9..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "Webpack", - "version": "0.0.0", - "devDependencies": { - "css-loader": "^0.23.1", - "extendify": "^1.0.0", - "extract-text-webpack-plugin": "^1.0.1", - "less": "^2.6.0", - "less-loader": "^2.2.2", - "style-loader": "^0.13.0", - "webpack-hot-middleware": "^2.7.1" - }, - "dependencies": { - "aspnet-prerendering": "^1.0.4", - "aspnet-webpack": "^1.0.3", - "ts-loader": "^0.8.1", - "typescript": "^2.0.0", - "webpack": "^1.13.3" - } -} diff --git a/src/Middleware/SpaServices/samples/Webpack/tsconfig.json b/src/Middleware/SpaServices/samples/Webpack/tsconfig.json deleted file mode 100644 index 453b7a3308..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "node", - "module": "commonjs", - "target": "es5", - "jsx": "preserve", - "sourceMap": true, - "lib": ["es6", "dom"] - }, - "exclude": [ - "node_modules" - ] -} diff --git a/src/Middleware/SpaServices/samples/Webpack/webpack.config.dev.js b/src/Middleware/SpaServices/samples/Webpack/webpack.config.dev.js deleted file mode 100644 index fc339d2e6e..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/webpack.config.dev.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - devtool: 'inline-source-map', - module: { - loaders: [ - { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' } - ] - } -}; diff --git a/src/Middleware/SpaServices/samples/Webpack/webpack.config.js b/src/Middleware/SpaServices/samples/Webpack/webpack.config.js deleted file mode 100644 index 011ed5f2e5..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/webpack.config.js +++ /dev/null @@ -1,25 +0,0 @@ -var path = require('path'); -var merge = require('extendify')({ isDeep: true, arrays: 'concat' }); -var devConfig = require('./webpack.config.dev'); -var prodConfig = require('./webpack.config.prod'); -var isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development'; - -module.exports = merge({ - resolve: { - extensions: [ '', '.js', '.jsx', '.ts', '.tsx' ] - }, - module: { - loaders: [ - { test: /\.ts(x?)$/, exclude: /node_modules/, loader: 'ts-loader?silent' } - ], - }, - entry: { - main: ['./Clientside/App.ts'] - }, - output: { - path: path.join(__dirname, 'wwwroot', 'dist'), - filename: '[name].js', - publicPath: '/dist/' - }, - plugins: [] -}, isDevelopment ? devConfig : prodConfig); diff --git a/src/Middleware/SpaServices/samples/Webpack/webpack.config.prod.js b/src/Middleware/SpaServices/samples/Webpack/webpack.config.prod.js deleted file mode 100644 index 56203448a9..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/webpack.config.prod.js +++ /dev/null @@ -1,15 +0,0 @@ -var webpack = require('webpack'); -var ExtractTextPlugin = require('extract-text-webpack-plugin'); -var extractLESS = new ExtractTextPlugin('my-styles.css'); - -module.exports = { - module: { - loaders: [ - { test: /\.less$/, loader: extractLESS.extract(['css-loader', 'less-loader']) }, - ] - }, - plugins: [ - extractLESS, - new webpack.optimize.UglifyJsPlugin({ minimize: true, compressor: { warnings: false } }) - ] -}; diff --git a/src/Middleware/SpaServices/samples/Webpack/wwwroot/favicon.ico b/src/Middleware/SpaServices/samples/Webpack/wwwroot/favicon.ico deleted file mode 100644 index a3a799985c..0000000000 Binary files a/src/Middleware/SpaServices/samples/Webpack/wwwroot/favicon.ico and /dev/null differ diff --git a/src/Middleware/SpaServices/samples/Webpack/wwwroot/web.config b/src/Middleware/SpaServices/samples/Webpack/wwwroot/web.config deleted file mode 100644 index e70a7778d6..0000000000 --- a/src/Middleware/SpaServices/samples/Webpack/wwwroot/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/Middleware/SpaServices/src/Prerendering/DefaultSpaPrerenderer.cs b/src/Middleware/SpaServices/src/Prerendering/DefaultSpaPrerenderer.cs index 022c39fc01..be38e0c0f5 100644 --- a/src/Middleware/SpaServices/src/Prerendering/DefaultSpaPrerenderer.cs +++ b/src/Middleware/SpaServices/src/Prerendering/DefaultSpaPrerenderer.cs @@ -1,3 +1,7 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.Threading; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -12,6 +16,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// server-side prerendering APIs. This is an alternative to prerendering via /// the asp-prerender-module tag helper. ///
+ [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] internal class DefaultSpaPrerenderer : ISpaPrerenderer { private readonly string _applicationBasePath; diff --git a/src/Middleware/SpaServices/src/Prerendering/ISpaPrerenderer.cs b/src/Middleware/SpaServices/src/Prerendering/ISpaPrerenderer.cs index 183d4ae632..dcf986673e 100644 --- a/src/Middleware/SpaServices/src/Prerendering/ISpaPrerenderer.cs +++ b/src/Middleware/SpaServices/src/Prerendering/ISpaPrerenderer.cs @@ -1,4 +1,8 @@ -using System.Threading.Tasks; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading.Tasks; namespace Microsoft.AspNetCore.SpaServices.Prerendering { @@ -7,6 +11,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// JavaScript-based Single Page Applications. This is an alternative /// to using the 'asp-prerender-module' tag helper. ///
+ [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public interface ISpaPrerenderer { /// diff --git a/src/Middleware/SpaServices/src/Prerendering/JavaScriptModuleExport.cs b/src/Middleware/SpaServices/src/Prerendering/JavaScriptModuleExport.cs index 97456b653d..13fd2177dd 100644 --- a/src/Middleware/SpaServices/src/Prerendering/JavaScriptModuleExport.cs +++ b/src/Middleware/SpaServices/src/Prerendering/JavaScriptModuleExport.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; namespace Microsoft.AspNetCore.SpaServices.Prerendering @@ -5,6 +8,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// /// Describes how to find the JavaScript code that performs prerendering. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public class JavaScriptModuleExport { /// @@ -27,4 +31,4 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// public string ExportName { get; set; } } -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/src/Prerendering/PrerenderTagHelper.cs b/src/Middleware/SpaServices/src/Prerendering/PrerenderTagHelper.cs index 665fbff8ef..3aaed1445a 100644 --- a/src/Middleware/SpaServices/src/Prerendering/PrerenderTagHelper.cs +++ b/src/Middleware/SpaServices/src/Prerendering/PrerenderTagHelper.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Threading; using System.Threading.Tasks; @@ -14,6 +17,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// A tag helper for prerendering JavaScript applications on the server. /// [HtmlTargetElement(Attributes = PrerenderModuleAttributeName)] + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public class PrerenderTagHelper : TagHelper { private const string PrerenderModuleAttributeName = "asp-prerender-module"; diff --git a/src/Middleware/SpaServices/src/Prerendering/Prerenderer.cs b/src/Middleware/SpaServices/src/Prerendering/Prerenderer.cs index 4e2fb16a42..26316320c6 100644 --- a/src/Middleware/SpaServices/src/Prerendering/Prerenderer.cs +++ b/src/Middleware/SpaServices/src/Prerendering/Prerenderer.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Threading; using System.Threading.Tasks; @@ -10,12 +13,14 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// /// Performs server-side prerendering by invoking code in Node.js. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static class Prerenderer { private static readonly object CreateNodeScriptLock = new object(); private static StringAsTempFile NodeScript; + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] internal static Task RenderToString( string applicationBasePath, INodeServices nodeServices, @@ -63,6 +68,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// The maximum duration to wait for prerendering to complete. /// The PathBase for the currently-executing HTTP request. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static Task RenderToString( string applicationBasePath, INodeServices nodeServices, @@ -88,7 +94,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering private static string GetNodeScriptFilename(CancellationToken applicationStoppingToken) { - lock(CreateNodeScriptLock) + lock (CreateNodeScriptLock) { if (NodeScript == null) { @@ -100,4 +106,4 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering return NodeScript.FileName; } } -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/src/Prerendering/PrerenderingServiceCollectionExtensions.cs b/src/Middleware/SpaServices/src/Prerendering/PrerenderingServiceCollectionExtensions.cs index d6a674396f..cabc57adcf 100644 --- a/src/Middleware/SpaServices/src/Prerendering/PrerenderingServiceCollectionExtensions.cs +++ b/src/Middleware/SpaServices/src/Prerendering/PrerenderingServiceCollectionExtensions.cs @@ -1,10 +1,15 @@ -using Microsoft.AspNetCore.SpaServices.Prerendering; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.SpaServices.Prerendering; namespace Microsoft.Extensions.DependencyInjection { /// /// Extension methods for setting up prerendering features in an . /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static class PrerenderingServiceCollectionExtensions { /// @@ -12,6 +17,7 @@ namespace Microsoft.Extensions.DependencyInjection /// of . /// /// The . + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void AddSpaPrerenderer(this IServiceCollection serviceCollection) { serviceCollection.AddHttpContextAccessor(); diff --git a/src/Middleware/SpaServices/src/Prerendering/RenderToStringResult.cs b/src/Middleware/SpaServices/src/Prerendering/RenderToStringResult.cs index 1a2e156354..f6f5d77911 100644 --- a/src/Middleware/SpaServices/src/Prerendering/RenderToStringResult.cs +++ b/src/Middleware/SpaServices/src/Prerendering/RenderToStringResult.cs @@ -1,3 +1,7 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Text; @@ -7,6 +11,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering /// /// Describes the prerendering result returned by JavaScript code. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public class RenderToStringResult { /// @@ -57,4 +62,4 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering return stringBuilder.ToString(); } } -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/src/Routing/SpaRouteConstraint.cs b/src/Middleware/SpaServices/src/Routing/SpaRouteConstraint.cs index d6a1d5b227..6f25a25379 100644 --- a/src/Middleware/SpaServices/src/Routing/SpaRouteConstraint.cs +++ b/src/Middleware/SpaServices/src/Routing/SpaRouteConstraint.cs @@ -1,9 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; namespace Microsoft.AspNetCore.SpaServices { + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] internal class SpaRouteConstraint : IRouteConstraint { private readonly string _clientRouteTokenName; @@ -34,4 +38,4 @@ namespace Microsoft.AspNetCore.SpaServices return uri.IndexOf('.', lastSegmentStartPos + 1) >= 0; } } -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/src/Routing/SpaRouteExtensions.cs b/src/Middleware/SpaServices/src/Routing/SpaRouteExtensions.cs index 7838aa13b9..547cf7c8ad 100644 --- a/src/Middleware/SpaServices/src/Routing/SpaRouteExtensions.cs +++ b/src/Middleware/SpaServices/src/Routing/SpaRouteExtensions.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Collections.Generic; using Microsoft.AspNetCore.Routing; @@ -10,6 +13,7 @@ namespace Microsoft.AspNetCore.Builder /// /// Extension methods useful for configuring routing in a single-page application (SPA). /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static class SpaRouteExtensions { private const string ClientRouteTokenName = "clientRoute"; @@ -91,4 +95,4 @@ namespace Microsoft.AspNetCore.Builder private static IDictionary ObjectToDictionary(object value) => value as IDictionary ?? new RouteValueDictionary(value); } -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/src/Webpack/ConditionalProxyMiddleware.cs b/src/Middleware/SpaServices/src/Webpack/ConditionalProxyMiddleware.cs index 8cfbd07a18..59623ad879 100644 --- a/src/Middleware/SpaServices/src/Webpack/ConditionalProxyMiddleware.cs +++ b/src/Middleware/SpaServices/src/Webpack/ConditionalProxyMiddleware.cs @@ -1,9 +1,11 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.SpaServices.Webpack @@ -14,6 +16,7 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack /// This is useful for Webpack middleware, because it lets you fall back on prebuilt files on disk for /// chunks not exposed by the current Webpack config (e.g., DLL/vendor chunks). /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] internal class ConditionalProxyMiddleware { private const int DefaultHttpBufferSize = 4096; @@ -89,7 +92,7 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack } // We can handle this - context.Response.StatusCode = (int) responseMessage.StatusCode; + context.Response.StatusCode = (int)responseMessage.StatusCode; foreach (var header in responseMessage.Headers) { context.Response.Headers[header.Key] = header.Value.ToArray(); @@ -120,4 +123,4 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack } } } -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/src/Webpack/ConditionalProxyMiddlewareOptions.cs b/src/Middleware/SpaServices/src/Webpack/ConditionalProxyMiddlewareOptions.cs index 2c3311aabd..7f6f80fd77 100644 --- a/src/Middleware/SpaServices/src/Webpack/ConditionalProxyMiddlewareOptions.cs +++ b/src/Middleware/SpaServices/src/Webpack/ConditionalProxyMiddlewareOptions.cs @@ -1,7 +1,11 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; namespace Microsoft.AspNetCore.SpaServices.Webpack { + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] internal class ConditionalProxyMiddlewareOptions { public ConditionalProxyMiddlewareOptions(string scheme, string host, string port, TimeSpan requestTimeout) @@ -17,4 +21,4 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack public string Port { get; } public TimeSpan RequestTimeout { get; } } -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/src/Webpack/WebpackDevMiddleware.cs b/src/Middleware/SpaServices/src/Webpack/WebpackDevMiddleware.cs index 2e8f92ea3c..1a39d2de20 100644 --- a/src/Middleware/SpaServices/src/Webpack/WebpackDevMiddleware.cs +++ b/src/Middleware/SpaServices/src/Webpack/WebpackDevMiddleware.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.IO; using System.Threading; @@ -11,6 +14,7 @@ namespace Microsoft.AspNetCore.Builder /// /// Extension methods that can be used to enable Webpack dev middleware support. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static class WebpackDevMiddleware { private const string DefaultConfigFile = "webpack.config.js"; @@ -36,6 +40,7 @@ namespace Microsoft.AspNetCore.Builder ///
/// The . /// Options for configuring the Webpack compiler instance. + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public static void UseWebpackDevMiddleware( this IApplicationBuilder appBuilder, WebpackDevMiddlewareOptions options = null) @@ -145,4 +150,4 @@ namespace Microsoft.AspNetCore.Builder } } #pragma warning restore CS0649 -} \ No newline at end of file +} diff --git a/src/Middleware/SpaServices/src/Webpack/WebpackDevMiddlewareOptions.cs b/src/Middleware/SpaServices/src/Webpack/WebpackDevMiddlewareOptions.cs index df50100dc7..28685e0d90 100644 --- a/src/Middleware/SpaServices/src/Webpack/WebpackDevMiddlewareOptions.cs +++ b/src/Middleware/SpaServices/src/Webpack/WebpackDevMiddlewareOptions.cs @@ -1,3 +1,7 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; using System.Collections.Generic; namespace Microsoft.AspNetCore.SpaServices.Webpack @@ -5,6 +9,7 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack /// /// Options for configuring a Webpack dev middleware compiler. /// + [Obsolete("Use Microsoft.AspNetCore.SpaServices.Extensions")] public class WebpackDevMiddlewareOptions { /// @@ -30,10 +35,10 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack /// public bool ReactHotModuleReplacement { get; set; } - /// + /// /// Specifies additional options to be passed to the Webpack Hot Middleware client, if used. - /// - public IDictionary HotModuleReplacementClientOptions { get; set; } + /// + public IDictionary HotModuleReplacementClientOptions { get; set; } /// /// Specifies the Webpack configuration file to be used. If not set, defaults to 'webpack.config.js'. @@ -58,4 +63,4 @@ namespace Microsoft.AspNetCore.SpaServices.Webpack /// public object EnvParam { get; set; } } -} \ No newline at end of file +} diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ActionSelectionTable.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ActionSelectionTable.cs index c028fcf6ed..4521e310ad 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/ActionSelectionTable.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/ActionSelectionTable.cs @@ -66,10 +66,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure // For action selection, ignore attribute routed actions items: actions.Items.Where(a => a.AttributeRouteInfo == null), - getRouteKeys: a => a.RouteValues.Keys, + getRouteKeys: a => a.RouteValues?.Keys, getRouteValue: (a, key) => { - a.RouteValues.TryGetValue(key, out var value); + string value = null; + a.RouteValues?.TryGetValue(key, out value); return value ?? string.Empty; }); } @@ -87,10 +88,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure return e.GetType() == typeof(Endpoint); }), - getRouteKeys: e => e.Metadata.GetMetadata().RouteValues.Keys, + getRouteKeys: e => e.Metadata.GetMetadata()?.RouteValues?.Keys, getRouteValue: (e, key) => { - e.Metadata.GetMetadata().RouteValues.TryGetValue(key, out var value); + string value = null; + e.Metadata.GetMetadata()?.RouteValues?.TryGetValue(key, out value); return Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty; }); } @@ -112,9 +114,13 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure foreach (var item in items) { - foreach (var key in getRouteKeys(item)) + var keys = getRouteKeys(item); + if (keys != null) { - routeKeys.Add(key); + foreach (var key in keys) + { + routeKeys.Add(key); + } } } diff --git a/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointMatcherPolicy.cs b/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointMatcherPolicy.cs index 369502d633..118a5b8e84 100644 --- a/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointMatcherPolicy.cs +++ b/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointMatcherPolicy.cs @@ -138,9 +138,12 @@ namespace Microsoft.AspNetCore.Mvc.Routing var values = new RouteValueDictionary(dynamicValues); // Include values that were matched by the fallback route. - foreach (var kvp in originalValues) + if (originalValues != null) { - values.TryAdd(kvp.Key, kvp.Value); + foreach (var kvp in originalValues) + { + values.TryAdd(kvp.Key, kvp.Value); + } } // Update the route values diff --git a/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointSelector.cs b/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointSelector.cs index fbe0337420..f07b22b94b 100644 --- a/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointSelector.cs +++ b/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointSelector.cs @@ -11,10 +11,17 @@ namespace Microsoft.AspNetCore.Mvc.Routing { internal class DynamicControllerEndpointSelector : IDisposable { - private readonly ControllerActionEndpointDataSource _dataSource; + private readonly EndpointDataSource _dataSource; private readonly DataSourceDependentCache> _cache; public DynamicControllerEndpointSelector(ControllerActionEndpointDataSource dataSource) + : this((EndpointDataSource)dataSource) + { + } + + // Exposed for tests. We need to accept a more specific type in the constructor for DI + // to work. + protected DynamicControllerEndpointSelector(EndpointDataSource dataSource) { if (dataSource == null) { diff --git a/src/Mvc/Mvc.Core/test/Routing/DynamicControllerEndpointMatcherPolicyTest.cs b/src/Mvc/Mvc.Core/test/Routing/DynamicControllerEndpointMatcherPolicyTest.cs new file mode 100644 index 0000000000..52e7dcece6 --- /dev/null +++ b/src/Mvc/Mvc.Core/test/Routing/DynamicControllerEndpointMatcherPolicyTest.cs @@ -0,0 +1,272 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Matching; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Routing +{ + public class DynamicControllerEndpointMatcherPolicyTest + { + public DynamicControllerEndpointMatcherPolicyTest() + { + var actions = new ActionDescriptor[] + { + new ControllerActionDescriptor() + { + RouteValues = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["action"] = "Index", + ["controller"] = "Home", + }, + }, + new ControllerActionDescriptor() + { + RouteValues = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["action"] = "About", + ["controller"] = "Home", + }, + }, + new ControllerActionDescriptor() + { + RouteValues = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["action"] = "Index", + ["controller"] = "Blog", + }, + } + }; + + ControllerEndpoints = new[] + { + new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(actions[0]), "Test1"), + new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(actions[1]), "Test2"), + new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(actions[2]), "Test3"), + }; + + DynamicEndpoint = new Endpoint( + _ => Task.CompletedTask, + new EndpointMetadataCollection(new object[] + { + new DynamicControllerRouteValueTransformerMetadata(typeof(CustomTransformer)), + }), + "dynamic"); + + DataSource = new DefaultEndpointDataSource(ControllerEndpoints); + + Selector = new TestDynamicControllerEndpointSelector(DataSource); + + var services = new ServiceCollection(); + services.AddRouting(); + services.AddScoped(s => + { + var transformer = new CustomTransformer(); + transformer.Transform = (c, values) => Transform(c, values); + return transformer; + }); + Services = services.BuildServiceProvider(); + + Comparer = Services.GetRequiredService(); + } + + private EndpointMetadataComparer Comparer { get; } + + private DefaultEndpointDataSource DataSource { get; } + + private Endpoint[] ControllerEndpoints { get; } + + private Endpoint DynamicEndpoint { get; } + + private DynamicControllerEndpointSelector Selector { get; } + + private IServiceProvider Services { get; } + + private Func> Transform { get; set; } + + [Fact] + public async Task ApplyAsync_NoMatch() + { + // Arrange + var policy = new DynamicControllerEndpointMatcherPolicy(Selector, Comparer); + + var endpoints = new[] { DynamicEndpoint, }; + var values = new RouteValueDictionary[] { null, }; + var scores = new[] { 0, }; + + var candidates = new CandidateSet(endpoints, values, scores); + candidates.SetValidity(0, false); + + Transform = (c, values) => + { + throw new InvalidOperationException(); + }; + + var httpContext = new DefaultHttpContext() + { + RequestServices = Services, + }; + + // Act + await policy.ApplyAsync(httpContext, candidates); + + // Assert + Assert.False(candidates.IsValidCandidate(0)); + } + + [Fact] + public async Task ApplyAsync_HasMatchNoEndpointFound() + { + // Arrange + var policy = new DynamicControllerEndpointMatcherPolicy(Selector, Comparer); + + var endpoints = new[] { DynamicEndpoint, }; + var values = new RouteValueDictionary[] { null, }; + var scores = new[] { 0, }; + + var candidates = new CandidateSet(endpoints, values, scores); + + Transform = (c, values) => + { + return new ValueTask(new RouteValueDictionary()); + }; + + var httpContext = new DefaultHttpContext() + { + RequestServices = Services, + }; + + // Act + await policy.ApplyAsync(httpContext, candidates); + + // Assert + Assert.Null(candidates[0].Endpoint); + Assert.Null(candidates[0].Values); + Assert.False(candidates.IsValidCandidate(0)); + } + + [Fact] + public async Task ApplyAsync_HasMatchFindsEndpoint_WithoutRouteValues() + { + // Arrange + var policy = new DynamicControllerEndpointMatcherPolicy(Selector, Comparer); + + var endpoints = new[] { DynamicEndpoint, }; + var values = new RouteValueDictionary[] { null, }; + var scores = new[] { 0, }; + + var candidates = new CandidateSet(endpoints, values, scores); + + Transform = (c, values) => + { + return new ValueTask(new RouteValueDictionary(new + { + controller = "Home", + action = "Index", + })); + }; + + var httpContext = new DefaultHttpContext() + { + RequestServices = Services, + }; + + // Act + await policy.ApplyAsync(httpContext, candidates); + + // Assert + Assert.Same(ControllerEndpoints[0], candidates[0].Endpoint); + Assert.Collection( + candidates[0].Values.OrderBy(kvp => kvp.Key), + kvp => + { + Assert.Equal("action", kvp.Key); + Assert.Equal("Index", kvp.Value); + }, + kvp => + { + Assert.Equal("controller", kvp.Key); + Assert.Equal("Home", kvp.Value); + }); + Assert.True(candidates.IsValidCandidate(0)); + } + + [Fact] + public async Task ApplyAsync_HasMatchFindsEndpoint_WithRouteValues() + { + // Arrange + var policy = new DynamicControllerEndpointMatcherPolicy(Selector, Comparer); + + var endpoints = new[] { DynamicEndpoint, }; + var values = new RouteValueDictionary[] { new RouteValueDictionary(new { slug = "test", }), }; + var scores = new[] { 0, }; + + var candidates = new CandidateSet(endpoints, values, scores); + + Transform = (c, values) => + { + return new ValueTask(new RouteValueDictionary(new + { + controller = "Home", + action = "Index", + })); + }; + + var httpContext = new DefaultHttpContext() + { + RequestServices = Services, + }; + + // Act + await policy.ApplyAsync(httpContext, candidates); + + // Assert + Assert.Same(ControllerEndpoints[0], candidates[0].Endpoint); + Assert.Collection( + candidates[0].Values.OrderBy(kvp => kvp.Key), + kvp => + { + Assert.Equal("action", kvp.Key); + Assert.Equal("Index", kvp.Value); + }, + kvp => + { + Assert.Equal("controller", kvp.Key); + Assert.Equal("Home", kvp.Value); + }, + kvp => + { + Assert.Equal("slug", kvp.Key); + Assert.Equal("test", kvp.Value); + }); + Assert.True(candidates.IsValidCandidate(0)); + } + + private class TestDynamicControllerEndpointSelector : DynamicControllerEndpointSelector + { + public TestDynamicControllerEndpointSelector(EndpointDataSource dataSource) + : base(dataSource) + { + } + } + + private class CustomTransformer : DynamicRouteValueTransformer + { + public Func> Transform { get; set; } + + public override ValueTask TransformAsync(HttpContext httpContext, RouteValueDictionary values) + { + return Transform(httpContext, values); + } + } + } +} diff --git a/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointMatcherPolicy.cs b/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointMatcherPolicy.cs index 6751d41658..ea68558d4b 100644 --- a/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointMatcherPolicy.cs +++ b/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointMatcherPolicy.cs @@ -146,9 +146,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure var values = new RouteValueDictionary(dynamicValues); // Include values that were matched by the fallback route. - foreach (var kvp in originalValues) + if (originalValues != null) { - values.TryAdd(kvp.Key, kvp.Value); + foreach (var kvp in originalValues) + { + values.TryAdd(kvp.Key, kvp.Value); + } } // Update the route values diff --git a/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointSelector.cs b/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointSelector.cs index 0e143db00b..b333f2947b 100644 --- a/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointSelector.cs +++ b/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointSelector.cs @@ -11,10 +11,17 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure { internal class DynamicPageEndpointSelector : IDisposable { - private readonly PageActionEndpointDataSource _dataSource; + private readonly EndpointDataSource _dataSource; private readonly DataSourceDependentCache> _cache; public DynamicPageEndpointSelector(PageActionEndpointDataSource dataSource) + : this((EndpointDataSource)dataSource) + { + } + + // Exposed for tests. We need to accept a more specific type in the constructor for DI + // to work. + protected DynamicPageEndpointSelector(EndpointDataSource dataSource) { if (dataSource == null) { diff --git a/src/Mvc/Mvc.RazorPages/test/Infrastructure/DynamicPageEndpointMatcherPolicyTest.cs b/src/Mvc/Mvc.RazorPages/test/Infrastructure/DynamicPageEndpointMatcherPolicyTest.cs new file mode 100644 index 0000000000..1cea019f5c --- /dev/null +++ b/src/Mvc/Mvc.RazorPages/test/Infrastructure/DynamicPageEndpointMatcherPolicyTest.cs @@ -0,0 +1,265 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Matching; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure +{ + public class DynamicPageEndpointMatcherPolicyTest + { + public DynamicPageEndpointMatcherPolicyTest() + { + var actions = new ActionDescriptor[] + { + new PageActionDescriptor() + { + RouteValues = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["page"] = "/Index", + }, + }, + new PageActionDescriptor() + { + RouteValues = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["page"] = "/About", + }, + }, + }; + + PageEndpoints = new[] + { + new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(actions[0]), "Test1"), + new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(actions[1]), "Test2"), + }; + + DynamicEndpoint = new Endpoint( + _ => Task.CompletedTask, + new EndpointMetadataCollection(new object[] + { + new DynamicPageRouteValueTransformerMetadata(typeof(CustomTransformer)), + }), + "dynamic"); + + DataSource = new DefaultEndpointDataSource(PageEndpoints); + + Selector = new TestDynamicPageEndpointSelector(DataSource); + + var services = new ServiceCollection(); + services.AddRouting(); + services.AddScoped(s => + { + var transformer = new CustomTransformer(); + transformer.Transform = (c, values) => Transform(c, values); + return transformer; + }); + Services = services.BuildServiceProvider(); + + Comparer = Services.GetRequiredService(); + + LoadedEndpoint = new Endpoint(_ => Task.CompletedTask, EndpointMetadataCollection.Empty, "Loaded"); + + var loader = new Mock(); + loader + .Setup(l => l.LoadAsync(It.IsAny())) + .Returns(Task.FromResult(new CompiledPageActionDescriptor() { Endpoint = LoadedEndpoint, })); + Loader = loader.Object; + + } + + private EndpointMetadataComparer Comparer { get; } + + private DefaultEndpointDataSource DataSource { get; } + + private Endpoint[] PageEndpoints { get; } + + private Endpoint DynamicEndpoint { get; } + + private Endpoint LoadedEndpoint { get; } + + private PageLoader Loader { get; } + + private DynamicPageEndpointSelector Selector { get; } + + private IServiceProvider Services { get; } + + private Func> Transform { get; set; } + + [Fact] + public async Task ApplyAsync_NoMatch() + { + // Arrange + var policy = new DynamicPageEndpointMatcherPolicy(Selector, Loader, Comparer); + + var endpoints = new[] { DynamicEndpoint, }; + var values = new RouteValueDictionary[] { null, }; + var scores = new[] { 0, }; + + var candidates = new CandidateSet(endpoints, values, scores); + candidates.SetValidity(0, false); + + Transform = (c, values) => + { + throw new InvalidOperationException(); + }; + + var httpContext = new DefaultHttpContext() + { + RequestServices = Services, + }; + + // Act + await policy.ApplyAsync(httpContext, candidates); + + // Assert + Assert.False(candidates.IsValidCandidate(0)); + } + + [Fact] + public async Task ApplyAsync_HasMatchNoEndpointFound() + { + // Arrange + var policy = new DynamicPageEndpointMatcherPolicy(Selector, Loader, Comparer); + + var endpoints = new[] { DynamicEndpoint, }; + var values = new RouteValueDictionary[] { null, }; + var scores = new[] { 0, }; + + var candidates = new CandidateSet(endpoints, values, scores); + + Transform = (c, values) => + { + return new ValueTask(new RouteValueDictionary()); + }; + + var httpContext = new DefaultHttpContext() + { + RequestServices = Services, + }; + + // Act + await policy.ApplyAsync(httpContext, candidates); + + // Assert + Assert.Null(candidates[0].Endpoint); + Assert.Null(candidates[0].Values); + Assert.False(candidates.IsValidCandidate(0)); + } + + [Fact] + public async Task ApplyAsync_HasMatchFindsEndpoint_WithoutRouteValues() + { + // Arrange + var policy = new DynamicPageEndpointMatcherPolicy(Selector, Loader, Comparer); + + var endpoints = new[] { DynamicEndpoint, }; + var values = new RouteValueDictionary[] { null, }; + var scores = new[] { 0, }; + + var candidates = new CandidateSet(endpoints, values, scores); + + Transform = (c, values) => + { + return new ValueTask(new RouteValueDictionary(new + { + page = "/Index", + })); + }; + + var httpContext = new DefaultHttpContext() + { + RequestServices = Services, + }; + + // Act + await policy.ApplyAsync(httpContext, candidates); + + // Assert + Assert.Same(LoadedEndpoint, candidates[0].Endpoint); + Assert.Collection( + candidates[0].Values.OrderBy(kvp => kvp.Key), + kvp => + { + Assert.Equal("page", kvp.Key); + Assert.Equal("/Index", kvp.Value); + }); + Assert.True(candidates.IsValidCandidate(0)); + } + + [Fact] + public async Task ApplyAsync_HasMatchFindsEndpoint_WithRouteValues() + { + // Arrange + var policy = new DynamicPageEndpointMatcherPolicy(Selector, Loader, Comparer); + + var endpoints = new[] { DynamicEndpoint, }; + var values = new RouteValueDictionary[] { new RouteValueDictionary(new { slug = "test", }), }; + var scores = new[] { 0, }; + + var candidates = new CandidateSet(endpoints, values, scores); + + Transform = (c, values) => + { + return new ValueTask(new RouteValueDictionary(new + { + page = "/Index", + })); + }; + + var httpContext = new DefaultHttpContext() + { + RequestServices = Services, + }; + + // Act + await policy.ApplyAsync(httpContext, candidates); + + // Assert + Assert.Same(LoadedEndpoint, candidates[0].Endpoint); + Assert.Collection( + candidates[0].Values.OrderBy(kvp => kvp.Key), + kvp => + { + Assert.Equal("page", kvp.Key); + Assert.Equal("/Index", kvp.Value); + }, + kvp => + { + Assert.Equal("slug", kvp.Key); + Assert.Equal("test", kvp.Value); + }); + Assert.True(candidates.IsValidCandidate(0)); + } + + private class TestDynamicPageEndpointSelector : DynamicPageEndpointSelector + { + public TestDynamicPageEndpointSelector(EndpointDataSource dataSource) + : base(dataSource) + { + } + } + + private class CustomTransformer : DynamicRouteValueTransformer + { + public Func> Transform { get; set; } + + public override ValueTask TransformAsync(HttpContext httpContext, RouteValueDictionary values) + { + return Transform(httpContext, values); + } + } + } +} diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/src/app/counter/counter.component.html b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/src/app/counter/counter.component.html index d37b212c4c..89b9c80ff8 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/src/app/counter/counter.component.html +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/src/app/counter/counter.component.html @@ -2,6 +2,6 @@

This is a simple example of an Angular component.

-

Current count: {{ currentCount }}

+

Current count: {{ currentCount }}

diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/src/app/fetch-data/fetch-data.component.html b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/src/app/fetch-data/fetch-data.component.html index cd33b58a5c..19b3835dbf 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/src/app/fetch-data/fetch-data.component.html +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/ClientApp/src/app/fetch-data/fetch-data.component.html @@ -1,10 +1,10 @@ -

Weather forecast

+

Weather forecast

This component demonstrates fetching data from the server.

Loading...

- +
diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/Startup.cs b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/Startup.cs index d6e4a775cc..053345327c 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/Startup.cs +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/Angular-CSharp/Startup.cs @@ -88,7 +88,10 @@ namespace Company.WebApplication1 #endif app.UseStaticFiles(); - app.UseSpaStaticFiles(); + if (!env.IsDevelopment()) + { + app.UseSpaStaticFiles(); + } app.UseRouting(); diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/Counter.js b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/Counter.js index 734887d18f..9a4ec746ba 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/Counter.js +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/Counter.js @@ -3,26 +3,26 @@ import React, { Component } from 'react'; export class Counter extends Component { static displayName = Counter.name; - constructor (props) { + constructor(props) { super(props); this.state = { currentCount: 0 }; this.incrementCounter = this.incrementCounter.bind(this); } - incrementCounter () { + incrementCounter() { this.setState({ currentCount: this.state.currentCount + 1 }); } - render () { + render() { return (

Counter

This is a simple example of a React component.

-

Current count: {this.state.currentCount}

+

Current count: {this.state.currentCount}

diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/FetchData.js b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/FetchData.js index 4782540e3b..d1a9f910d0 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/FetchData.js +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/React-CSharp/ClientApp/src/components/FetchData.js @@ -17,7 +17,7 @@ export class FetchData extends Component { static renderForecastsTable(forecasts) { return ( -
Date
+
@@ -47,7 +47,7 @@ export class FetchData extends Component { return (
-

Weather forecast

+

Weather forecast

This component demonstrates fetching data from the server.

{contents}
diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/Counter.tsx b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/Counter.tsx index a31720c44b..82fde952e6 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/Counter.tsx +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/Counter.tsx @@ -17,11 +17,11 @@ class Counter extends React.PureComponent {

This is a simple example of a React component.

-

Current count: {this.props.count}

+

Current count: {this.props.count}

diff --git a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/FetchData.tsx b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/FetchData.tsx index c177f0bc67..9fed830288 100644 --- a/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/FetchData.tsx +++ b/src/ProjectTemplates/Web.Spa.ProjectTemplates/content/ReactRedux-CSharp/ClientApp/src/components/FetchData.tsx @@ -7,78 +7,78 @@ import * as WeatherForecastsStore from '../store/WeatherForecasts'; // At runtime, Redux will merge together... type WeatherForecastProps = - WeatherForecastsStore.WeatherForecastsState // ... state we've requested from the Redux store - & typeof WeatherForecastsStore.actionCreators // ... plus action creators we've requested - & RouteComponentProps<{ startDateIndex: string }>; // ... plus incoming routing parameters + WeatherForecastsStore.WeatherForecastsState // ... state we've requested from the Redux store + & typeof WeatherForecastsStore.actionCreators // ... plus action creators we've requested + & RouteComponentProps<{ startDateIndex: string }>; // ... plus incoming routing parameters class FetchData extends React.PureComponent { - // This method is called when the component is first added to the document - public componentDidMount() { - this.ensureDataFetched(); - } + // This method is called when the component is first added to the document + public componentDidMount() { + this.ensureDataFetched(); + } - // This method is called when the route parameters change - public componentDidUpdate() { - this.ensureDataFetched(); - } + // This method is called when the route parameters change + public componentDidUpdate() { + this.ensureDataFetched(); + } - public render() { - return ( - -

Weather forecast

-

This component demonstrates fetching data from the server and working with URL parameters.

- { this.renderForecastsTable() } - { this.renderPagination() } -
- ); - } + public render() { + return ( + +

Weather forecast

+

This component demonstrates fetching data from the server and working with URL parameters.

+ {this.renderForecastsTable()} + {this.renderPagination()} +
+ ); + } - private ensureDataFetched() { - const startDateIndex = parseInt(this.props.match.params.startDateIndex, 10) || 0; - this.props.requestWeatherForecasts(startDateIndex); - } + private ensureDataFetched() { + const startDateIndex = parseInt(this.props.match.params.startDateIndex, 10) || 0; + this.props.requestWeatherForecasts(startDateIndex); + } - private renderForecastsTable() { - return ( -
Date
- - - - - - - - - - {this.props.forecasts.map((forecast: WeatherForecastsStore.WeatherForecast) => - - - - - - - )} - -
DateTemp. (C)Temp. (F)Summary
{forecast.date}{forecast.temperatureC}{forecast.temperatureF}{forecast.summary}
- ); - } + private renderForecastsTable() { + return ( + + + + + + + + + + + {this.props.forecasts.map((forecast: WeatherForecastsStore.WeatherForecast) => + + + + + + + )} + +
DateTemp. (C)Temp. (F)Summary
{forecast.date}{forecast.temperatureC}{forecast.temperatureF}{forecast.summary}
+ ); + } - private renderPagination() { - const prevStartDateIndex = (this.props.startDateIndex || 0) - 5; - const nextStartDateIndex = (this.props.startDateIndex || 0) + 5; + private renderPagination() { + const prevStartDateIndex = (this.props.startDateIndex || 0) - 5; + const nextStartDateIndex = (this.props.startDateIndex || 0) + 5; - return ( -
- Previous - {this.props.isLoading && Loading...} - Next -
- ); - } + return ( +
+ Previous + {this.props.isLoading && Loading...} + Next +
+ ); + } } export default connect( - (state: ApplicationState) => state.weatherForecasts, // Selects which state properties are merged into the component's props - WeatherForecastsStore.actionCreators // Selects which action creators are merged into the component's props + (state: ApplicationState) => state.weatherForecasts, // Selects which state properties are merged into the component's props + WeatherForecastsStore.actionCreators // Selects which action creators are merged into the component's props )(FetchData as any); diff --git a/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets b/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets index 566502471f..df2b4e5e1b 100644 --- a/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets +++ b/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets @@ -6,7 +6,7 @@ Condition="$(DesignTimeBuild) != true"> - RestoreAdditionalProjectSources=$([MSBuild]::Escape("$(ArtifactsShippingPackagesDir);$(ArtifactsNonShippingPackagesDir)")); + RestoreAdditionalProjectSources=$([MSBuild]::Escape("$(RestoreAdditionalProjectSources);$(ArtifactsShippingPackagesDir);$(ArtifactsNonShippingPackagesDir)")); MicrosoftNetCompilersToolsetPackageVersion=$(MicrosoftNetCompilersToolsetPackageVersion); MicrosoftNETCoreAppRuntimeVersion=$(MicrosoftNETCoreAppRuntimeVersion); MicrosoftNETCoreAppRefPackageVersion=$(MicrosoftNETCoreAppRefPackageVersion); diff --git a/src/ProjectTemplates/test/SpaTemplateTest/SpaTemplateTestBase.cs b/src/ProjectTemplates/test/SpaTemplateTest/SpaTemplateTestBase.cs index 7095ce5d5a..c019aad9c7 100644 --- a/src/ProjectTemplates/test/SpaTemplateTest/SpaTemplateTestBase.cs +++ b/src/ProjectTemplates/test/SpaTemplateTest/SpaTemplateTestBase.cs @@ -45,7 +45,7 @@ namespace Templates.Test.SpaTemplateTest { Project = await ProjectFactory.GetOrCreateProject(key, Output); - var createResult = await Project.RunDotNetNewAsync(template, auth: usesAuth ? "Individual" : null, language: null, useLocalDb); + using var createResult = await Project.RunDotNetNewAsync(template, auth: usesAuth ? "Individual" : null, language: null, useLocalDb); Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult)); // We shouldn't have to do the NPM restore in tests because it should happen @@ -61,26 +61,26 @@ namespace Templates.Test.SpaTemplateTest Assert.Contains(".db", projectFileContents); } - var npmRestoreResult = await Project.RestoreWithRetryAsync(Output, clientAppSubdirPath); + using var npmRestoreResult = await Project.RestoreWithRetryAsync(Output, clientAppSubdirPath); Assert.True(0 == npmRestoreResult.ExitCode, ErrorMessages.GetFailedProcessMessage("npm restore", Project, npmRestoreResult)); - var lintResult = await ProcessEx.RunViaShellAsync(Output, clientAppSubdirPath, "npm run lint"); + using var lintResult = await ProcessEx.RunViaShellAsync(Output, clientAppSubdirPath, "npm run lint"); Assert.True(0 == lintResult.ExitCode, ErrorMessages.GetFailedProcessMessage("npm run lint", Project, lintResult)); if (template == "react" || template == "reactredux") { - var testResult = await ProcessEx.RunViaShellAsync(Output, clientAppSubdirPath, "npm run test"); + using var testResult = await ProcessEx.RunViaShellAsync(Output, clientAppSubdirPath, "npm run test"); Assert.True(0 == testResult.ExitCode, ErrorMessages.GetFailedProcessMessage("npm run test", Project, testResult)); } - var publishResult = await Project.RunDotNetPublishAsync(); + using var publishResult = await Project.RunDotNetPublishAsync(); Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult)); // Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release // The output from publish will go into bin/Release/netcoreapp3.0/publish and won't be affected by calling build // later, while the opposite is not true. - var buildResult = await Project.RunDotNetBuildAsync(); + using var buildResult = await Project.RunDotNetBuildAsync(); Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult)); // localdb is not installed on the CI machines, so skip it. @@ -88,13 +88,13 @@ namespace Templates.Test.SpaTemplateTest if (usesAuth) { - var migrationsResult = await Project.RunDotNetEfCreateMigrationAsync(template); + using var migrationsResult = await Project.RunDotNetEfCreateMigrationAsync(template); Assert.True(0 == migrationsResult.ExitCode, ErrorMessages.GetFailedProcessMessage("run EF migrations", Project, migrationsResult)); Project.AssertEmptyMigration(template); if (shouldVisitFetchData) { - var dbUpdateResult = await Project.RunDotNetEfUpdateDatabaseAsync(); + using var dbUpdateResult = await Project.RunDotNetEfUpdateDatabaseAsync(); Assert.True(0 == dbUpdateResult.ExitCode, ErrorMessages.GetFailedProcessMessage("update database", Project, dbUpdateResult)); } } @@ -247,7 +247,7 @@ namespace Templates.Test.SpaTemplateTest browser.Equal("Weather forecast", () => browser.FindElement(By.TagName("h1")).Text); // Asynchronously loads and displays the table of weather forecasts - browser.Exists(By.CssSelector("table>tbody>tr")); + browser.Exists(By.CssSelector("table>tbody>tr"), TimeSpan.FromSeconds(10)); browser.Equal(5, () => browser.FindElements(By.CssSelector("p+table>tbody>tr")).Count); } diff --git a/src/Security/Authentication/Negotiate/samples/NegotiateAuthSample/Startup.cs b/src/Security/Authentication/Negotiate/samples/NegotiateAuthSample/Startup.cs index 1643abe614..2e62846f8f 100644 --- a/src/Security/Authentication/Negotiate/samples/NegotiateAuthSample/Startup.cs +++ b/src/Security/Authentication/Negotiate/samples/NegotiateAuthSample/Startup.cs @@ -20,7 +20,17 @@ namespace NegotiateAuthSample options.FallbackPolicy = options.DefaultPolicy; }); services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) - .AddNegotiate(); + .AddNegotiate(options => + { + options.Events = new NegotiateEvents() + { + OnAuthenticationFailed = context => + { + // context.SkipHandler(); + return Task.CompletedTask; + } + }; + }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) diff --git a/src/Security/Authentication/Negotiate/src/Internal/INegotiateState.cs b/src/Security/Authentication/Negotiate/src/Internal/INegotiateState.cs index dbc215ef7d..d2eb518c5b 100644 --- a/src/Security/Authentication/Negotiate/src/Internal/INegotiateState.cs +++ b/src/Security/Authentication/Negotiate/src/Internal/INegotiateState.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate // For testing internal interface INegotiateState : IDisposable { - string GetOutgoingBlob(string incomingBlob); + string GetOutgoingBlob(string incomingBlob, out BlobErrorType status, out Exception error); bool IsCompleted { get; } @@ -17,4 +17,12 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate IIdentity GetIdentity(); } + + internal enum BlobErrorType + { + None, + CredentialError, + ClientError, + Other + } } diff --git a/src/Security/Authentication/Negotiate/src/Internal/NegotiateLoggingExtensions.cs b/src/Security/Authentication/Negotiate/src/Internal/NegotiateLoggingExtensions.cs index 11141bb123..b39ec8cf7b 100644 --- a/src/Security/Authentication/Negotiate/src/Internal/NegotiateLoggingExtensions.cs +++ b/src/Security/Authentication/Negotiate/src/Internal/NegotiateLoggingExtensions.cs @@ -12,6 +12,8 @@ namespace Microsoft.Extensions.Logging private static Action _enablingCredentialPersistence; private static Action _disablingCredentialPersistence; private static Action _exceptionProcessingAuth; + private static Action _credentialError; + private static Action _clientError; private static Action _challengeNegotiate; private static Action _reauthenticating; private static Action _deferring; @@ -50,6 +52,14 @@ namespace Microsoft.Extensions.Logging eventId: new EventId(8, "Deferring"), logLevel: LogLevel.Information, formatString: "Deferring to the server's implementation of Windows Authentication."); + _credentialError = LoggerMessage.Define( + eventId: new EventId(9, "CredentialError"), + logLevel: LogLevel.Debug, + formatString: "There was a problem with the users credentials."); + _clientError = LoggerMessage.Define( + eventId: new EventId(10, "ClientError"), + logLevel: LogLevel.Debug, + formatString: "The users authentication request was invalid."); } public static void IncompleteNegotiateChallenge(this ILogger logger) @@ -75,5 +85,11 @@ namespace Microsoft.Extensions.Logging public static void Deferring(this ILogger logger) => _deferring(logger, null); + + public static void CredentialError(this ILogger logger, Exception ex) + => _credentialError(logger, ex); + + public static void ClientError(this ILogger logger, Exception ex) + => _clientError(logger, ex); } } diff --git a/src/Security/Authentication/Negotiate/src/Internal/ReflectedNegotiateState.cs b/src/Security/Authentication/Negotiate/src/Internal/ReflectedNegotiateState.cs index 37a1dff6f0..fb7a6a3a9f 100644 --- a/src/Security/Authentication/Negotiate/src/Internal/ReflectedNegotiateState.cs +++ b/src/Security/Authentication/Negotiate/src/Internal/ReflectedNegotiateState.cs @@ -5,6 +5,8 @@ using System; using System.Linq; using System.Net; using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; using System.Security.Authentication; using System.Security.Principal; @@ -12,21 +14,30 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate { internal class ReflectedNegotiateState : INegotiateState { + // https://www.gnu.org/software/gss/reference/gss.pdf + private const uint GSS_S_NO_CRED = 7 << 16; + private static readonly ConstructorInfo _constructor; private static readonly MethodInfo _getOutgoingBlob; private static readonly MethodInfo _isCompleted; private static readonly MethodInfo _protocol; private static readonly MethodInfo _getIdentity; private static readonly MethodInfo _closeContext; + private static readonly FieldInfo _statusCode; + private static readonly FieldInfo _statusException; + private static readonly MethodInfo _getException; + private static readonly FieldInfo _gssMinorStatus; + private static readonly Type _gssExceptionType; private readonly object _instance; static ReflectedNegotiateState() { - var ntAuthType = typeof(AuthenticationException).Assembly.GetType("System.Net.NTAuthentication"); + var secAssembly = typeof(AuthenticationException).Assembly; + var ntAuthType = secAssembly.GetType("System.Net.NTAuthentication", throwOnError: true); _constructor = ntAuthType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).First(); _getOutgoingBlob = ntAuthType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(info => - info.Name.Equals("GetOutgoingBlob") && info.GetParameters().Count() == 2).Single(); + info.Name.Equals("GetOutgoingBlob") && info.GetParameters().Count() == 3).Single(); _isCompleted = ntAuthType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(info => info.Name.Equals("get_IsCompleted")).Single(); _protocol = ntAuthType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(info => @@ -34,9 +45,23 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate _closeContext = ntAuthType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(info => info.Name.Equals("CloseContext")).Single(); - var negoStreamPalType = typeof(AuthenticationException).Assembly.GetType("System.Net.Security.NegotiateStreamPal"); + var securityStatusType = secAssembly.GetType("System.Net.SecurityStatusPal", throwOnError: true); + _statusCode = securityStatusType.GetField("ErrorCode"); + _statusException = securityStatusType.GetField("Exception"); + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var interopType = secAssembly.GetType("Interop", throwOnError: true); + var netNativeType = interopType.GetNestedType("NetSecurityNative", BindingFlags.NonPublic | BindingFlags.Static); + _gssExceptionType = netNativeType.GetNestedType("GssApiException", BindingFlags.NonPublic); + _gssMinorStatus = _gssExceptionType.GetField("_minorStatus", BindingFlags.Instance | BindingFlags.NonPublic); + } + + var negoStreamPalType = secAssembly.GetType("System.Net.Security.NegotiateStreamPal", throwOnError: true); _getIdentity = negoStreamPalType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(info => info.Name.Equals("GetIdentity")).Single(); + _getException = negoStreamPalType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(info => + info.Name.Equals("CreateExceptionFromError")).Single(); } public ReflectedNegotiateState() @@ -50,14 +75,15 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate // The client doesn't need the context once auth is complete, but the server does. // I'm not sure why it auto-closes for the client given that the client closes it just a few lines later. // https://github.com/dotnet/corefx/blob/a3ab91e10045bb298f48c1d1f9bd5b0782a8ac46/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs#L134 - public string GetOutgoingBlob(string incomingBlob) + public string GetOutgoingBlob(string incomingBlob, out BlobErrorType status, out Exception error) { byte[] decodedIncomingBlob = null; if (incomingBlob != null && incomingBlob.Length > 0) { decodedIncomingBlob = Convert.FromBase64String(incomingBlob); } - byte[] decodedOutgoingBlob = GetOutgoingBlob(decodedIncomingBlob, true); + + byte[] decodedOutgoingBlob = GetOutgoingBlob(decodedIncomingBlob, out status, out error); string outgoingBlob = null; if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) @@ -68,9 +94,65 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate return outgoingBlob; } - private byte[] GetOutgoingBlob(byte[] incomingBlob, bool thrownOnError) + private byte[] GetOutgoingBlob(byte[] incomingBlob, out BlobErrorType status, out Exception error) { - return (byte[])_getOutgoingBlob.Invoke(_instance, new object[] { incomingBlob, thrownOnError }); + try + { + // byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) + var parameters = new object[] { incomingBlob, false, null }; + var blob = (byte[])_getOutgoingBlob.Invoke(_instance, parameters); + + var securityStatus = parameters[2]; + // TODO: Update after corefx changes + error = (Exception)(_statusException.GetValue(securityStatus) + ?? _getException.Invoke(null, new[] { securityStatus })); + var errorCode = (SecurityStatusPalErrorCode)_statusCode.GetValue(securityStatus); + + // TODO: Remove after corefx changes + // The linux implementation always uses InternalError; + if (errorCode == SecurityStatusPalErrorCode.InternalError + && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + && _gssExceptionType.IsInstanceOfType(error)) + { + var majorStatus = (uint)error.HResult; + var minorStatus = (uint)_gssMinorStatus.GetValue(error); + + // Remap specific errors + if (majorStatus == GSS_S_NO_CRED && minorStatus == 0) + { + errorCode = SecurityStatusPalErrorCode.UnknownCredentials; + } + + error = new Exception($"An authentication exception occured (0x{majorStatus:X}/0x{minorStatus:X}).", error); + } + + if (errorCode == SecurityStatusPalErrorCode.OK + || errorCode == SecurityStatusPalErrorCode.ContinueNeeded + || errorCode == SecurityStatusPalErrorCode.CompleteNeeded) + { + status = BlobErrorType.None; + } + else if (IsCredentialError(errorCode)) + { + status = BlobErrorType.CredentialError; + } + else if (IsClientError(errorCode)) + { + status = BlobErrorType.ClientError; + } + else + { + status = BlobErrorType.Other; + } + + return blob; + } + catch (TargetInvocationException tex) + { + // Unwrap + ExceptionDispatchInfo.Capture(tex.InnerException).Throw(); + throw; + } } public bool IsCompleted @@ -92,5 +174,36 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate { _closeContext.Invoke(_instance, Array.Empty()); } + + private bool IsCredentialError(SecurityStatusPalErrorCode error) + { + return error == SecurityStatusPalErrorCode.LogonDenied || + error == SecurityStatusPalErrorCode.UnknownCredentials || + error == SecurityStatusPalErrorCode.NoImpersonation || + error == SecurityStatusPalErrorCode.NoAuthenticatingAuthority || + error == SecurityStatusPalErrorCode.UntrustedRoot || + error == SecurityStatusPalErrorCode.CertExpired || + error == SecurityStatusPalErrorCode.SmartcardLogonRequired || + error == SecurityStatusPalErrorCode.BadBinding; + } + + private bool IsClientError(SecurityStatusPalErrorCode error) + { + return error == SecurityStatusPalErrorCode.InvalidToken || + error == SecurityStatusPalErrorCode.CannotPack || + error == SecurityStatusPalErrorCode.QopNotSupported || + error == SecurityStatusPalErrorCode.NoCredentials || + error == SecurityStatusPalErrorCode.MessageAltered || + error == SecurityStatusPalErrorCode.OutOfSequence || + error == SecurityStatusPalErrorCode.IncompleteMessage || + error == SecurityStatusPalErrorCode.IncompleteCredentials || + error == SecurityStatusPalErrorCode.WrongPrincipal || + error == SecurityStatusPalErrorCode.TimeSkew || + error == SecurityStatusPalErrorCode.IllegalMessage || + error == SecurityStatusPalErrorCode.CertUnknown || + error == SecurityStatusPalErrorCode.AlgorithmMismatch || + error == SecurityStatusPalErrorCode.SecurityQosFailed || + error == SecurityStatusPalErrorCode.UnsupportedPreauth; + } } } diff --git a/src/Security/Authentication/Negotiate/src/Internal/SecurityStatusPalErrorCode.cs b/src/Security/Authentication/Negotiate/src/Internal/SecurityStatusPalErrorCode.cs new file mode 100644 index 0000000000..f89a996e7e --- /dev/null +++ b/src/Security/Authentication/Negotiate/src/Internal/SecurityStatusPalErrorCode.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Authentication.Negotiate +{ + internal enum SecurityStatusPalErrorCode + { + NotSet = 0, + OK, + ContinueNeeded, + CompleteNeeded, + CompAndContinue, + ContextExpired, + CredentialsNeeded, + Renegotiate, + + // Errors + OutOfMemory, + InvalidHandle, + Unsupported, + TargetUnknown, + InternalError, + PackageNotFound, + NotOwner, + CannotInstall, + InvalidToken, + CannotPack, + QopNotSupported, + NoImpersonation, + LogonDenied, + UnknownCredentials, + NoCredentials, + MessageAltered, + OutOfSequence, + NoAuthenticatingAuthority, + IncompleteMessage, + IncompleteCredentials, + BufferNotEnough, + WrongPrincipal, + TimeSkew, + UntrustedRoot, + IllegalMessage, + CertUnknown, + CertExpired, + DecryptFailure, + AlgorithmMismatch, + SecurityQosFailed, + SmartcardLogonRequired, + UnsupportedPreauth, + BadBinding, + DowngradeDetected, + ApplicationProtocolMismatch + } +} diff --git a/src/Security/Authentication/Negotiate/src/NegotiateHandler.cs b/src/Security/Authentication/Negotiate/src/NegotiateHandler.cs index e49cd5cd97..c880fb1564 100644 --- a/src/Security/Authentication/Negotiate/src/NegotiateHandler.cs +++ b/src/Security/Authentication/Negotiate/src/NegotiateHandler.cs @@ -65,6 +65,8 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate /// True if a response was generated, false otherwise. public async Task HandleRequestAsync() { + AuthPersistence persistence = null; + bool authFailedEventCalled = false; try { if (_requestProcessed || Options.DeferToServer) @@ -86,7 +88,7 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate } var connectionItems = GetConnectionItems(); - var persistence = (AuthPersistence)connectionItems[AuthPersistenceKey]; + persistence = (AuthPersistence)connectionItems[AuthPersistenceKey]; _negotiateState = persistence?.State; var authorizationHeader = Request.Headers[HeaderNames.Authorization]; @@ -126,7 +128,40 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate _negotiateState ??= Options.StateFactory.CreateInstance(); - var outgoing = _negotiateState.GetOutgoingBlob(token); + var outgoing = _negotiateState.GetOutgoingBlob(token, out var errorType, out var exception); + Logger.LogInformation(errorType.ToString()); + if (errorType != BlobErrorType.None) + { + _negotiateState.Dispose(); + _negotiateState = null; + if (persistence?.State != null) + { + persistence.State.Dispose(); + persistence.State = null; + } + + if (errorType == BlobErrorType.CredentialError) + { + Logger.CredentialError(exception); + authFailedEventCalled = true; // Could throw, and we don't want to double trigger the event. + var result = await InvokeAuthenticateFailedEvent(exception); + return result ?? false; // Default to skipping the handler, let AuthZ generate a new 401 + } + else if (errorType == BlobErrorType.ClientError) + { + Logger.ClientError(exception); + authFailedEventCalled = true; // Could throw, and we don't want to double trigger the event. + var result = await InvokeAuthenticateFailedEvent(exception); + if (result.HasValue) + { + return result.Value; + } + Context.Response.StatusCode = StatusCodes.Status400BadRequest; + return true; // Default to terminating request + } + + throw exception; + } if (!_negotiateState.IsCompleted) { @@ -193,24 +228,26 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate } catch (Exception ex) { - Logger.ExceptionProcessingAuth(ex); - var errorContext = new AuthenticationFailedContext(Context, Scheme, Options) { Exception = ex }; - await Events.AuthenticationFailed(errorContext); - - if (errorContext.Result != null) + if (authFailedEventCalled) { - if (errorContext.Result.Handled) - { - return true; - } - else if (errorContext.Result.Skipped) - { - return false; - } - else if (errorContext.Result.Failure != null) - { - throw new Exception("An error was returned from the AuthenticationFailed event.", errorContext.Result.Failure); - } + throw; + } + + Logger.ExceptionProcessingAuth(ex); + + // Clear state so it's possible to retry on the same connection. + _negotiateState?.Dispose(); + _negotiateState = null; + if (persistence?.State != null) + { + persistence.State.Dispose(); + persistence.State = null; + } + + var result = await InvokeAuthenticateFailedEvent(ex); + if (result.HasValue) + { + return result.Value; } throw; @@ -219,6 +256,30 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate return false; } + private async Task InvokeAuthenticateFailedEvent(Exception ex) + { + var errorContext = new AuthenticationFailedContext(Context, Scheme, Options) { Exception = ex }; + await Events.AuthenticationFailed(errorContext); + + if (errorContext.Result != null) + { + if (errorContext.Result.Handled) + { + return true; + } + else if (errorContext.Result.Skipped) + { + return false; + } + else if (errorContext.Result.Failure != null) + { + throw new Exception("An error was returned from the AuthenticationFailed event.", errorContext.Result.Failure); + } + } + + return null; + } + /// /// Checks if the current request is authenticated and returns the user. /// diff --git a/src/Security/Authentication/Negotiate/test/Negotiate.Test/EventTests.cs b/src/Security/Authentication/Negotiate/test/Negotiate.Test/EventTests.cs index dc76aacb6e..6c3baef320 100644 --- a/src/Security/Authentication/Negotiate/test/Negotiate.Test/EventTests.cs +++ b/src/Security/Authentication/Negotiate/test/Negotiate.Test/EventTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Reflection.Metadata; using System.Security.Principal; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; @@ -71,16 +72,16 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate } [Fact] - public async Task OnAuthenticationFailed_Fires() + public async Task OnAuthenticationFailed_FromException_Fires() { - var eventInvoked = false; + var eventInvoked = 0; using var host = await CreateHostAsync(options => { options.Events = new NegotiateEvents() { OnAuthenticationFailed = context => { - eventInvoked = true; + eventInvoked++; Assert.IsType(context.Exception); Assert.Equal("InvalidBlob", context.Exception.Message); return Task.CompletedTask; @@ -92,11 +93,11 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate var ex = await Assert.ThrowsAsync(() => SendAsync(server, "/404", new TestConnection(), "Negotiate InvalidBlob")); Assert.Equal("InvalidBlob", ex.Message); - Assert.True(eventInvoked); + Assert.Equal(1, eventInvoked); } [Fact] - public async Task OnAuthenticationFailed_Handled() + public async Task OnAuthenticationFailed_FromException_Handled() { using var host = await CreateHostAsync(options => { @@ -104,7 +105,7 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate { OnAuthenticationFailed = context => { - context.Response.StatusCode = StatusCodes.Status418ImATeapot; ; + context.Response.StatusCode = StatusCodes.Status418ImATeapot; context.Response.Headers[HeaderNames.WWWAuthenticate] = "Teapot"; context.HandleResponse(); return Task.CompletedTask; @@ -118,6 +119,157 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate Assert.Equal("Teapot", result.Response.Headers[HeaderNames.WWWAuthenticate]); } + [Fact] + public async Task OnAuthenticationFailed_FromOtherBlobError_Fires() + { + var eventInvoked = 0; + using var host = await CreateHostAsync(options => + { + options.Events = new NegotiateEvents() + { + OnAuthenticationFailed = context => + { + eventInvoked++; + Assert.IsType(context.Exception); + Assert.Equal("A test other error occured", context.Exception.Message); + return Task.CompletedTask; + } + }; + }); + var server = host.GetTestServer(); + + var ex = await Assert.ThrowsAsync(() => + SendAsync(server, "/404", new TestConnection(), "Negotiate OtherError")); + Assert.Equal("A test other error occured", ex.Message); + Assert.Equal(1, eventInvoked); + } + + [Fact] + public async Task OnAuthenticationFailed_FromOtherBlobError_Handled() + { + var eventInvoked = 0; + using var host = await CreateHostAsync(options => + { + options.Events = new NegotiateEvents() + { + OnAuthenticationFailed = context => + { + eventInvoked++; + context.Response.StatusCode = StatusCodes.Status418ImATeapot; + context.Response.Headers[HeaderNames.WWWAuthenticate] = "Teapot"; + context.HandleResponse(); + return Task.CompletedTask; + } + }; + }); + var server = host.GetTestServer(); + + var result = await SendAsync(server, "/404", new TestConnection(), "Negotiate OtherError"); + Assert.Equal(StatusCodes.Status418ImATeapot, result.Response.StatusCode); + Assert.Equal("Teapot", result.Response.Headers[HeaderNames.WWWAuthenticate]); + Assert.Equal(1, eventInvoked); + } + + [Fact] + public async Task OnAuthenticationFailed_FromCredentialError_Fires() + { + var eventInvoked = 0; + using var host = await CreateHostAsync(options => + { + options.Events = new NegotiateEvents() + { + OnAuthenticationFailed = context => + { + eventInvoked++; + Assert.IsType(context.Exception); + Assert.Equal("A test credential error occured", context.Exception.Message); + return Task.CompletedTask; + } + }; + }); + var server = host.GetTestServer(); + + var response = await SendAsync(server, "/418", new TestConnection(), "Negotiate CredentialError"); + Assert.Equal(StatusCodes.Status418ImATeapot, response.Response.StatusCode); + Assert.Equal(1, eventInvoked); + } + + [Fact] + public async Task OnAuthenticationFailed_FromCredentialError_Handled() + { + var eventInvoked = 0; + using var host = await CreateHostAsync(options => + { + options.Events = new NegotiateEvents() + { + OnAuthenticationFailed = context => + { + eventInvoked++; + context.Response.StatusCode = StatusCodes.Status418ImATeapot; + context.Response.Headers[HeaderNames.WWWAuthenticate] = "Teapot"; + context.HandleResponse(); + return Task.CompletedTask; + } + }; + }); + var server = host.GetTestServer(); + + var result = await SendAsync(server, "/404", new TestConnection(), "Negotiate CredentialError"); + Assert.Equal(StatusCodes.Status418ImATeapot, result.Response.StatusCode); + Assert.Equal("Teapot", result.Response.Headers[HeaderNames.WWWAuthenticate]); + Assert.Equal(1, eventInvoked); + } + + [Fact] + public async Task OnAuthenticationFailed_FromClientError_Fires() + { + var eventInvoked = 0; + using var host = await CreateHostAsync(options => + { + options.Events = new NegotiateEvents() + { + OnAuthenticationFailed = context => + { + eventInvoked++; + Assert.IsType(context.Exception); + Assert.Equal("A test client error occured", context.Exception.Message); + return Task.CompletedTask; + } + }; + }); + var server = host.GetTestServer(); + + var response = await SendAsync(server, "/404", new TestConnection(), "Negotiate ClientError"); + Assert.Equal(StatusCodes.Status400BadRequest, response.Response.StatusCode); + Assert.Equal(1, eventInvoked); + } + + [Fact] + public async Task OnAuthenticationFailed_FromClientError_Handled() + { + var eventInvoked = 0; + using var host = await CreateHostAsync(options => + { + options.Events = new NegotiateEvents() + { + OnAuthenticationFailed = context => + { + eventInvoked++; + context.Response.StatusCode = StatusCodes.Status418ImATeapot; + context.Response.Headers[HeaderNames.WWWAuthenticate] = "Teapot"; + context.HandleResponse(); + return Task.CompletedTask; + } + }; + }); + var server = host.GetTestServer(); + + var result = await SendAsync(server, "/404", new TestConnection(), "Negotiate ClientError"); + Assert.Equal(StatusCodes.Status418ImATeapot, result.Response.StatusCode); + Assert.Equal("Teapot", result.Response.Headers[HeaderNames.WWWAuthenticate]); + Assert.Equal(1, eventInvoked); + } + [Fact] public async Task OnAuthenticated_FiresOncePerRequest() { @@ -278,6 +430,12 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate Assert.False(string.IsNullOrEmpty(name), "name"); await context.Response.WriteAsync(name); }); + + builder.Map("/418", context => + { + context.Response.StatusCode = StatusCodes.Status418ImATeapot; + return Task.CompletedTask; + }); } private static Task SendAsync(TestServer server, string path, TestConnection connection, string authorizationHeader = null) @@ -352,7 +510,7 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate return new GenericIdentity("name", _protocol); } - public string GetOutgoingBlob(string incomingBlob) + public string GetOutgoingBlob(string incomingBlob, out BlobErrorType errorType, out Exception ex) { if (IsDisposed) { @@ -362,6 +520,10 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate { throw new InvalidOperationException("Authentication is already complete."); } + + errorType = BlobErrorType.None; + ex = null; + switch (incomingBlob) { case "ClientNtlmBlob1": @@ -391,8 +553,22 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate Assert.Equal("Kerberos", _protocol); IsCompleted = true; return "ServerKerberosBlob2"; + case "CredentialError": + errorType = BlobErrorType.CredentialError; + ex = new Exception("A test credential error occured"); + return null; + case "ClientError": + errorType = BlobErrorType.ClientError; + ex = new Exception("A test client error occured"); + return null; + case "OtherError": + errorType = BlobErrorType.Other; + ex = new Exception("A test other error occured"); + return null; default: - throw new InvalidOperationException(incomingBlob); + errorType = BlobErrorType.Other; + ex = new InvalidOperationException(incomingBlob); + return null; } } } diff --git a/src/Security/Authentication/Negotiate/test/Negotiate.Test/NegotiateHandlerTests.cs b/src/Security/Authentication/Negotiate/test/Negotiate.Test/NegotiateHandlerTests.cs index b57a8e996d..d696cd0afd 100644 --- a/src/Security/Authentication/Negotiate/test/Negotiate.Test/NegotiateHandlerTests.cs +++ b/src/Security/Authentication/Negotiate/test/Negotiate.Test/NegotiateHandlerTests.cs @@ -271,6 +271,39 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate Assert.False(result.Response.Headers.ContainsKey(HeaderNames.WWWAuthenticate)); } + [Fact] + public async Task CredentialError_401() + { + using var host = await CreateHostAsync(); + var server = host.GetTestServer(); + var testConnection = new TestConnection(); + var result = await SendAsync(server, "/Authenticate", testConnection, "Negotiate CredentialError"); + Assert.Equal(StatusCodes.Status401Unauthorized, result.Response.StatusCode); + Assert.Equal("Negotiate", result.Response.Headers[HeaderNames.WWWAuthenticate]); + } + + [Fact] + public async Task ClientError_400() + { + using var host = await CreateHostAsync(); + var server = host.GetTestServer(); + var testConnection = new TestConnection(); + var result = await SendAsync(server, "/404", testConnection, "Negotiate ClientError"); + Assert.Equal(StatusCodes.Status400BadRequest, result.Response.StatusCode); + Assert.DoesNotContain(HeaderNames.WWWAuthenticate, result.Response.Headers); + } + + [Fact] + public async Task OtherError_Throws() + { + using var host = await CreateHostAsync(); + var server = host.GetTestServer(); + var testConnection = new TestConnection(); + + var ex = await Assert.ThrowsAsync(() => SendAsync(server, "/404", testConnection, "Negotiate OtherError")); + Assert.Equal("A test other error occured", ex.Message); + } + // Single Stage private static async Task KerberosAuth(TestServer server, TestConnection testConnection) { @@ -474,7 +507,7 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate return new GenericIdentity("name", _protocol); } - public string GetOutgoingBlob(string incomingBlob) + public string GetOutgoingBlob(string incomingBlob, out BlobErrorType errorType, out Exception ex) { if (IsDisposed) { @@ -484,6 +517,10 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate { throw new InvalidOperationException("Authentication is already complete."); } + + errorType = BlobErrorType.None; + ex = null; + switch (incomingBlob) { case "ClientNtlmBlob1": @@ -513,8 +550,22 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate Assert.Equal("Kerberos", _protocol); IsCompleted = true; return "ServerKerberosBlob2"; + case "CredentialError": + errorType = BlobErrorType.CredentialError; + ex = new Exception("A test credential error occured"); + return null; + case "ClientError": + errorType = BlobErrorType.ClientError; + ex = new Exception("A test client error occured"); + return null; + case "OtherError": + errorType = BlobErrorType.Other; + ex = new Exception("A test other error occured"); + return null; default: - throw new InvalidOperationException(incomingBlob); + errorType = BlobErrorType.Other; + ex = new InvalidOperationException(incomingBlob); + return null; } } } diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.cpp index b05a4d1a50..545791610b 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.cpp @@ -30,16 +30,17 @@ void HostFxrErrorRedirector::HostFxrErrorRedirectorCallback(const WCHAR* message m_writeFunction->Append(std::wstring(message) + L"\r\n"); } -void HostFxr::Load() -{ - HMODULE hModule; - THROW_LAST_ERROR_IF(!GetModuleHandleEx(0, L"hostfxr.dll", &hModule)); - Load(hModule); -} - void HostFxr::Load(HMODULE moduleHandle) { + // A hostfxr may already be loaded here if we tried to start with an + // invalid configuration. Release hostfxr before loading it again. + if (m_hHostFxrDll != nullptr) + { + m_hHostFxrDll.release(); + } + m_hHostFxrDll = moduleHandle; + try { m_hostfxr_get_native_search_directories_fn = ModuleHelpers::GetKnownProcAddress(moduleHandle, "hostfxr_get_native_search_directories"); @@ -63,9 +64,13 @@ void HostFxr::Load(HMODULE moduleHandle) void HostFxr::Load(const std::wstring& location) { + // Make sure to always load hostfxr via an absolute path. + // If the process fails to start for whatever reason, a mismatched hostfxr + // may be already loaded in the process. try { HMODULE hModule; + LOG_INFOF(L"Loading hostfxr from location %s", location.c_str()); THROW_LAST_ERROR_IF_NULL(hModule = LoadLibraryW(location.c_str())); Load(hModule); } diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h index 526222322e..ced4dd1940 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxr.h @@ -60,7 +60,6 @@ public: { } - void Load(); void Load(HMODULE moduleHandle); void Load(const std::wstring& location); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp index 5707e4cd77..b671e7dba2 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp @@ -210,7 +210,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication() hostFxrResolutionResult->GetArguments(context->m_argc, context->m_argv); THROW_IF_FAILED(SetEnvironmentVariablesOnWorkerProcess()); - context->m_hostFxr.Load(); + context->m_hostFxr.Load(hostFxrResolutionResult->GetHostFxrLocation()); } else { diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs b/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs index b08ba18738..acac067a25 100644 --- a/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs +++ b/src/Servers/IIS/IntegrationTesting.IIS/src/IISExpressDeployer.cs @@ -94,10 +94,9 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS RunWebConfigActions(contentRoot); - var testUri = TestUriHelper.BuildTestUri(ServerType.IISExpress, DeploymentParameters.ApplicationBaseUriHint); // Launch the host process. - var (actualUri, hostExitToken) = await StartIISExpressAsync(testUri, contentRoot); + var (actualUri, hostExitToken) = await StartIISExpressAsync(contentRoot); Logger.LogInformation("Application ready at URL: {appUrl}", actualUri); @@ -152,27 +151,28 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS return dllRoot; } - private async Task<(Uri url, CancellationToken hostExitToken)> StartIISExpressAsync(Uri uri, string contentRoot) + private async Task<(Uri url, CancellationToken hostExitToken)> StartIISExpressAsync(string contentRoot) { using (Logger.BeginScope("StartIISExpress")) { - var port = uri.Port; - if (port == 0) - { - port = (uri.Scheme == "https") ? TestPortHelper.GetNextSSLPort() : TestPortHelper.GetNextPort(); - } - - Logger.LogInformation("Attempting to start IIS Express on port: {port}", port); - PrepareConfig(contentRoot, port); - - var parameters = string.IsNullOrEmpty(DeploymentParameters.ServerConfigLocation) ? - string.Format("/port:{0} /path:\"{1}\" /trace:error /systray:false", uri.Port, contentRoot) : - string.Format("/site:{0} /config:{1} /trace:error /systray:false", DeploymentParameters.SiteName, DeploymentParameters.ServerConfigLocation); - var iisExpressPath = GetIISExpressPath(); for (var attempt = 0; attempt < MaximumAttempts; attempt++) { + var uri = TestUriHelper.BuildTestUri(ServerType.IISExpress, DeploymentParameters.ApplicationBaseUriHint); + var port = uri.Port; + if (port == 0) + { + port = (uri.Scheme == "https") ? TestPortHelper.GetNextSSLPort() : TestPortHelper.GetNextPort(); + } + + Logger.LogInformation("Attempting to start IIS Express on port: {port}", port); + PrepareConfig(contentRoot, port); + + var parameters = string.IsNullOrEmpty(DeploymentParameters.ServerConfigLocation) ? + string.Format("/port:{0} /path:\"{1}\" /trace:error /systray:false", uri.Port, contentRoot) : + string.Format("/site:{0} /config:{1} /trace:error /systray:false", DeploymentParameters.SiteName, DeploymentParameters.ServerConfigLocation); + Logger.LogInformation("Executing command : {iisExpress} {parameters}", iisExpressPath, parameters); var startInfo = new ProcessStartInfo @@ -264,8 +264,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS Logger.LogInformation("Started iisexpress successfully. Process Id : {processId}, Port: {port}", _hostProcess.Id, port); return (url: url, hostExitToken: hostExitTokenSource.Token); } - - ChangePort(contentRoot, (uri.Scheme == "https") ? TestPortHelper.GetNextSSLPort() : TestPortHelper.GetNextPort()); } var message = $"Failed to initialize IIS Express after {MaximumAttempts} attempts to select a port"; @@ -315,14 +313,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS File.WriteAllText(DeploymentParameters.ServerConfigLocation, serverConfig); } - private void ChangePort(string contentRoot, int port) - { - var serverConfig = File.ReadAllText(DeploymentParameters.ServerConfigLocation); - XDocument config = XDocument.Parse(serverConfig); - ConfigureModuleAndBinding(config.Root, contentRoot, port); - File.WriteAllText(DeploymentParameters.ServerConfigLocation, serverConfig); - } - private void AddAspNetCoreElement(XElement config) { var aspNetCore = config diff --git a/src/Servers/Kestrel/test/FunctionalTests/UnixDomainSocketsTests.cs b/src/Servers/Kestrel/test/FunctionalTests/UnixDomainSocketsTests.cs index 4aff039e72..02ff378b17 100644 --- a/src/Servers/Kestrel/test/FunctionalTests/UnixDomainSocketsTests.cs +++ b/src/Servers/Kestrel/test/FunctionalTests/UnixDomainSocketsTests.cs @@ -84,20 +84,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests using (var host = hostBuilder.Build()) { - await host.StartAsync(); + await host.StartAsync().DefaultTimeout(); using (var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified)) { - await socket.ConnectAsync(new UnixDomainSocketEndPoint(path)); + await socket.ConnectAsync(new UnixDomainSocketEndPoint(path)).DefaultTimeout(); var data = Encoding.ASCII.GetBytes("Hello World"); - await socket.SendAsync(data, SocketFlags.None); + await socket.SendAsync(data, SocketFlags.None).DefaultTimeout(); var buffer = new byte[data.Length]; var read = 0; while (read < data.Length) { - read += await socket.ReceiveAsync(buffer.AsMemory(read, buffer.Length - read), SocketFlags.None); + read += await socket.ReceiveAsync(buffer.AsMemory(read, buffer.Length - read), SocketFlags.None).DefaultTimeout(); } Assert.Equal(data, buffer); @@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests // Wait for the server to complete the loop because of the FIN await serverConnectionCompletedTcs.Task.DefaultTimeout(); - await host.StopAsync(); + await host.StopAsync().DefaultTimeout(); } } finally diff --git a/src/Shared/E2ETesting/WaitAssert.cs b/src/Shared/E2ETesting/WaitAssert.cs index ded27f289f..42b9934b37 100644 --- a/src/Shared/E2ETesting/WaitAssert.cs +++ b/src/Shared/E2ETesting/WaitAssert.cs @@ -42,7 +42,10 @@ namespace Microsoft.AspNetCore.E2ETesting => WaitAssertCore(driver, () => Assert.Single(actualValues())); public static void Exists(this IWebDriver driver, By finder) - => WaitAssertCore(driver, () => Assert.NotEmpty(driver.FindElements(finder))); + => Exists(driver, finder, default); + + public static void Exists(this IWebDriver driver, By finder, TimeSpan timeout) + => WaitAssertCore(driver, () => Assert.NotEmpty(driver.FindElements(finder)), timeout); private static void WaitAssertCore(IWebDriver driver, Action assertion, TimeSpan timeout = default) { diff --git a/src/SignalR/clients/csharp/Client/test/UnitTests/HttpConnectionTests.ConnectionLifecycle.cs b/src/SignalR/clients/csharp/Client/test/UnitTests/HttpConnectionTests.ConnectionLifecycle.cs index 142063ab05..1c2280e42d 100644 --- a/src/SignalR/clients/csharp/Client/test/UnitTests/HttpConnectionTests.ConnectionLifecycle.cs +++ b/src/SignalR/clients/csharp/Client/test/UnitTests/HttpConnectionTests.ConnectionLifecycle.cs @@ -427,6 +427,89 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests } } + [Fact] + public async Task CancellationTokenFromStartPassedToTransport() + { + using (StartVerifiableLog()) + { + var cts = new CancellationTokenSource(); + var httpHandler = new TestHttpMessageHandler(); + + await WithConnectionAsync( + CreateConnection(httpHandler, + transport: new TestTransport(onTransportStart: () => { + // Cancel the token when the transport is starting which will fail the startTask. + cts.Cancel(); + return Task.CompletedTask; + })), + async (connection) => + { + // We aggregate failures that happen when we start the transport. The operation cancelled exception will + // be an inner exception. + var ex = await Assert.ThrowsAsync(async () => await connection.StartAsync(cts.Token)).OrTimeout(); + Assert.Equal(3, ex.InnerExceptions.Count); + var innerEx = ex.InnerExceptions[2]; + var innerInnerEx = innerEx.InnerException; + Assert.IsType(innerInnerEx); + }); + } + } + + [Fact] + public async Task SSECanBeCanceled() + { + bool ExpectedErrors(WriteContext writeContext) + { + return writeContext.LoggerName == typeof(HttpConnection).FullName && + writeContext.EventId.Name == "ErrorStartingTransport"; + } + + using (StartVerifiableLog(expectedErrorsFilter: ExpectedErrors)) + { + var httpHandler = new TestHttpMessageHandler(); + httpHandler.OnGet("/?id=00000000-0000-0000-0000-000000000000", (_, __) => + { + // Simulating a cancellationToken canceling this request. + throw new OperationCanceledException("Cancel SSE Start."); + }); + + var sse = new ServerSentEventsTransport(new HttpClient(httpHandler), LoggerFactory); + + await WithConnectionAsync( + CreateConnection(httpHandler, loggerFactory: LoggerFactory, transport: sse, transportType: HttpTransportType.ServerSentEvents), + async (connection) => + { + var ex = await Assert.ThrowsAsync(async () => await connection.StartAsync()).OrTimeout(); + }); + } + } + + [Fact] + public async Task LongPollingTransportCanBeCanceled() + { + using (StartVerifiableLog()) + { + var cts = new CancellationTokenSource(); + + var httpHandler = new TestHttpMessageHandler(autoNegotiate: false); + httpHandler.OnNegotiate((request, cancellationToken) => + { + // Cancel token so that the first request poll will throw + cts.Cancel(); + return ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent()); + }); + + var lp = new LongPollingTransport(new HttpClient(httpHandler)); + + await WithConnectionAsync( + CreateConnection(httpHandler, transport: lp, transportType: HttpTransportType.LongPolling), + async (connection) => + { + var ex = await Assert.ThrowsAsync(async () => await connection.StartAsync(cts.Token).OrTimeout()); + }); + } + } + private static async Task AssertDisposedAsync(HttpConnection connection) { var exception = diff --git a/src/SignalR/clients/csharp/Client/test/UnitTests/TestHttpMessageHandler.cs b/src/SignalR/clients/csharp/Client/test/UnitTests/TestHttpMessageHandler.cs index 75472a4970..06d05da7f5 100644 --- a/src/SignalR/clients/csharp/Client/test/UnitTests/TestHttpMessageHandler.cs +++ b/src/SignalR/clients/csharp/Client/test/UnitTests/TestHttpMessageHandler.cs @@ -46,6 +46,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests var firstPoll = true; OnRequest(async (request, next, cancellationToken) => { + cancellationToken.ThrowIfCancellationRequested(); if (ResponseUtils.IsLongPollRequest(request) && firstPoll) { firstPoll = false; @@ -156,6 +157,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests { OnRequest((request, next, cancellationToken) => { + cancellationToken.ThrowIfCancellationRequested(); if (request.Method.Equals(method) && string.Equals(request.RequestUri.PathAndQuery, pathAndQuery)) { return handler(request, cancellationToken); diff --git a/src/SignalR/clients/csharp/Client/test/UnitTests/TestTransport.cs b/src/SignalR/clients/csharp/Client/test/UnitTests/TestTransport.cs index ae1249dba7..35847771ae 100644 --- a/src/SignalR/clients/csharp/Client/test/UnitTests/TestTransport.cs +++ b/src/SignalR/clients/csharp/Client/test/UnitTests/TestTransport.cs @@ -44,6 +44,9 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests Application = pair.Application; await _startHandler(); + // To test canceling the token from the onTransportStart Func. + cancellationToken.ThrowIfCancellationRequested(); + // Start a loop to read from the pipe Receiving = ReceiveLoop(); async Task ReceiveLoop() diff --git a/src/SignalR/perf/benchmarkapps/BenchmarkServer/BenchmarkServer.csproj b/src/SignalR/perf/benchmarkapps/BenchmarkServer/BenchmarkServer.csproj deleted file mode 100644 index 4bcf55a1a2..0000000000 --- a/src/SignalR/perf/benchmarkapps/BenchmarkServer/BenchmarkServer.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - netcoreapp3.0 - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Directory.Build.props b/src/SignalR/perf/benchmarkapps/BenchmarkServer/Directory.Build.props deleted file mode 100644 index 8c119d5413..0000000000 --- a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Directory.Build.props +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Directory.Build.targets b/src/SignalR/perf/benchmarkapps/BenchmarkServer/Directory.Build.targets deleted file mode 100644 index 2e3fb2fa71..0000000000 --- a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Directory.Build.targets +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Hubs/EchoHub.cs b/src/SignalR/perf/benchmarkapps/BenchmarkServer/Hubs/EchoHub.cs deleted file mode 100644 index f6336fab84..0000000000 --- a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Hubs/EchoHub.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.SignalR; - -namespace BenchmarkServer.Hubs -{ - public class EchoHub : Hub - { - public async Task Broadcast(int duration) - { - var sent = 0; - try - { - var t = new CancellationTokenSource(); - t.CancelAfter(TimeSpan.FromSeconds(duration)); - while (!t.IsCancellationRequested && !Context.ConnectionAborted.IsCancellationRequested) - { - await Clients.All.SendAsync("send", DateTime.UtcNow); - sent++; - } - } - catch (Exception e) - { - Console.WriteLine(e); - } - Console.WriteLine("Broadcast exited: Sent {0} messages", sent); - } - - public DateTime Echo(DateTime time) - { - return time; - } - - public Task EchoAll(DateTime time) - { - return Clients.All.SendAsync("send", time); - } - - public void SendPayload(string payload) - { - // Dump the payload, we don't care - } - - public DateTime GetCurrentTime() - { - return DateTime.UtcNow; - } - } -} diff --git a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Program.cs b/src/SignalR/perf/benchmarkapps/BenchmarkServer/Program.cs deleted file mode 100644 index 0232643b58..0000000000 --- a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Program.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; - -namespace BenchmarkServer -{ - public class Program - { - public static void Main(string[] args) - { - Console.WriteLine($"Process ID: {Process.GetCurrentProcess().Id}"); - - var config = new ConfigurationBuilder() - .AddEnvironmentVariables(prefix: "ASPNETCORE_") - .AddCommandLine(args) - .Build(); - - var host = new WebHostBuilder() - .UseConfiguration(config) - .ConfigureLogging(loggerFactory => - { - if (Enum.TryParse(config["LogLevel"], out LogLevel logLevel)) - { - loggerFactory.AddConsole().SetMinimumLevel(logLevel); - } - }) - .UseKestrel() - .UseStartup(); - - host.Build().Run(); - } - } -} diff --git a/src/SignalR/perf/benchmarkapps/BenchmarkServer/README.md b/src/SignalR/perf/benchmarkapps/BenchmarkServer/README.md deleted file mode 100644 index e4f8ceb7a3..0000000000 --- a/src/SignalR/perf/benchmarkapps/BenchmarkServer/README.md +++ /dev/null @@ -1,17 +0,0 @@ -## Purpose - -This project is to assist in Benchmarking SignalR. -It makes it easier to test local changes than having the App in the Benchmarks repo by letting us make changes in signalr branches and using the example commandline below to run the benchmarks against our branches. - -The SignalRWorker that runs against this server is located at https://github.com/aspnet/benchmarks/blob/master/src/BenchmarksClient/Workers/SignalRWorker.cs. - -## Usage - -1. Push changes you would like to test to a branch on GitHub -2. Clone aspnet/benchmarks repo to your machine or install the global BenchmarksDriver tool https://www.nuget.org/packages/BenchmarksDriver/ -3. If cloned go to the BenchmarksDriver project -4. Use the following command as a guideline for running a test using your changes - -`benchmarks --server --client -p TransportType=WebSockets -p HubProtocol=messagepack -j https://raw.githubusercontent.com/aspnet/SignalR/dev/benchmarks/BenchmarkServer/signalr.json` - -5. For more info/commands see https://github.com/aspnet/benchmarks/blob/master/src/BenchmarksDriver/README.md diff --git a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Startup.cs b/src/SignalR/perf/benchmarkapps/BenchmarkServer/Startup.cs deleted file mode 100644 index 139ec09d47..0000000000 --- a/src/SignalR/perf/benchmarkapps/BenchmarkServer/Startup.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using BenchmarkServer.Hubs; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace BenchmarkServer -{ - public class Startup - { - private readonly IConfiguration _config; - public Startup(IConfiguration configuration) - { - _config = configuration; - } - - public void ConfigureServices(IServiceCollection services) - { - var signalrBuilder = services.AddSignalR(o => - { - o.EnableDetailedErrors = true; - }) - // TODO: Json vs NewtonsoftJson option - .AddMessagePackProtocol(); - - var redisConnectionString = _config["SignalRRedis"]; - if (!string.IsNullOrEmpty(redisConnectionString)) - { - signalrBuilder.AddStackExchangeRedis(redisConnectionString); - } - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - app.UseSignalR(routes => - { - routes.MapHub("/echo", o => - { - // Remove backpressure for benchmarking - o.TransportMaxBufferSize = 0; - o.ApplicationMaxBufferSize = 0; - }); - }); - } - } -} diff --git a/src/SignalR/perf/benchmarkapps/BenchmarkServer/signalr.json b/src/SignalR/perf/benchmarkapps/BenchmarkServer/signalr.json deleted file mode 100644 index 9fc37041b3..0000000000 --- a/src/SignalR/perf/benchmarkapps/BenchmarkServer/signalr.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "Default": { - "Client": "SignalR", - "Source": { - "Repository": "https://github.com/aspnet/aspnetcore.git", - "BranchOrCommit": "master", - "Project": "src/SignalR/perf/benchmarkapps/BenchmarkServer/BenchmarkServer.csproj" - }, - "Connections": 10, - "Duration": 20, - "Warmup": 2, - "Path": "/echo", - "ClientProperties": { - "CollectLatency": "true" - } - }, - "SignalRBroadcast": { - "ClientProperties": { "Scenario": "broadcast" } - }, - "SignalREcho": { - "ClientProperties": { "Scenario": "echo" } - }, - "SignalREchoAll": { - "ClientProperties": { "Scenario": "echoAll" }, - "Warmup": 0 - }, - "SignalREchoIdle": { - "ClientProperties": { - "Scenario": "echoIdle", - "CollectLatency": "false" - } - } -} diff --git a/src/SignalR/perf/benchmarkapps/NuGet.Config b/src/SignalR/perf/benchmarkapps/NuGet.Config deleted file mode 100644 index 298193b812..0000000000 --- a/src/SignalR/perf/benchmarkapps/NuGet.Config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs b/src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs index 89c7f77498..d8c1292d5a 100644 --- a/src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs +++ b/src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs @@ -91,6 +91,16 @@ namespace Microsoft.AspNetCore.SignalR.Tests return 43; } + public ValueTask ValueTaskMethod() + { + return new ValueTask(Task.CompletedTask); + } + + public ValueTask ValueTaskValueMethod() + { + return new ValueTask(43); + } + [HubMethodName("RenamedMethod")] public int ATestMethodThatIsRenamedByTheAttribute() { @@ -1050,4 +1060,32 @@ namespace Microsoft.AspNetCore.SignalR.Tests public bool TokenStateInDisconnected { get; set; } } + + public class CallerServiceHub : Hub + { + private readonly CallerService _service; + + public CallerServiceHub(CallerService service) + { + _service = service; + } + + public override Task OnConnectedAsync() + { + _service.SetCaller(Clients.Caller); + var tcs = (TaskCompletionSource)Context.Items["ConnectedTask"]; + tcs?.TrySetResult(true); + return base.OnConnectedAsync(); + } + } + + public class CallerService + { + public IClientProxy Caller { get; private set; } + + public void SetCaller(IClientProxy caller) + { + Caller = caller; + } + } } diff --git a/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs b/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs index f2eb574c9d..389e760f6c 100644 --- a/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs +++ b/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs @@ -814,6 +814,57 @@ namespace Microsoft.AspNetCore.SignalR.Tests } } + [Fact] + public async Task HubMethodCanReturnValueFromValueTask() + { + using (StartVerifiableLog()) + { + var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(null, LoggerFactory); + + var connectionHandler = serviceProvider.GetService>(); + + using (var client = new TestClient()) + { + var connectionHandlerTask = await client.ConnectAsync(connectionHandler); + + var result = (await client.InvokeAsync(nameof(MethodHub.ValueTaskValueMethod)).OrTimeout()).Result; + + // json serializer makes this a long + Assert.Equal(43L, result); + + // kill the connection + client.Dispose(); + + await connectionHandlerTask.OrTimeout(); + } + } + } + + [Fact] + public async Task HubMethodCanReturnValueTask() + { + using (StartVerifiableLog()) + { + var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(null, LoggerFactory); + + var connectionHandler = serviceProvider.GetService>(); + + using (var client = new TestClient()) + { + var connectionHandlerTask = await client.ConnectAsync(connectionHandler); + + var result = (await client.InvokeAsync(nameof(MethodHub.ValueTaskMethod)).OrTimeout()).Result; + + Assert.Null(result); + + // kill the connection + client.Dispose(); + + await connectionHandlerTask.OrTimeout(); + } + } + } + [Theory] [MemberData(nameof(HubTypes))] public async Task HubMethodsAreCaseInsensitive(Type hubType) @@ -3625,6 +3676,35 @@ namespace Microsoft.AspNetCore.SignalR.Tests } } + [Fact] + public async Task ClientsCallerPropertyCanBeUsedOutsideOfHub() + { + CallerService callerService = new CallerService(); + var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(services => + { + services.AddSingleton(callerService); + }); + var connectionHandler = serviceProvider.GetService>(); + + using (StartVerifiableLog()) + { + using (var client = new TestClient()) + { + var connectionHandlerTask = await client.ConnectAsync(connectionHandler); + + // Wait for a connection, or for the endpoint to fail. + await client.Connected.OrThrowIfOtherFails(connectionHandlerTask).OrTimeout(); + + await callerService.Caller.SendAsync("Echo", "message").OrTimeout(); + + var message = Assert.IsType(await client.ReadAsync().OrTimeout()); + + Assert.Equal("Echo", message.Target); + Assert.Equal("message", message.Arguments[0]); + } + } + } + private class CustomHubActivator : IHubActivator where THub : Hub { public int ReleaseCount; diff --git a/src/SiteExtensions/LoggingAggregate/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj b/src/SiteExtensions/LoggingAggregate/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj index 8444f35904..7b880e889b 100644 --- a/src/SiteExtensions/LoggingAggregate/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj +++ b/src/SiteExtensions/LoggingAggregate/src/Microsoft.AspNetCore.AzureAppServices.SiteExtension/Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj @@ -17,7 +17,7 @@ true - $(ArtifactsNonShippingPackagesDir) + $(RestoreAdditionalProjectSources);$(ArtifactsNonShippingPackagesDir) diff --git a/src/SiteExtensions/Sdk/SiteExtension.targets b/src/SiteExtensions/Sdk/SiteExtension.targets index 304dfdd917..320ea9fb3d 100644 --- a/src/SiteExtensions/Sdk/SiteExtension.targets +++ b/src/SiteExtensions/Sdk/SiteExtension.targets @@ -15,6 +15,7 @@ <_RuntimeStoreManifestFile>$(_DepsOutputDirectory)\rs.csproj <_RuntimeStoreOutput>$(_DepsOutputDirectory)\rs\ <_RsRestoreSources> + $(RestoreAdditionalProjectSources); $(ArtifactsShippingPackagesDir); $(ArtifactsNonShippingPackagesDir)