@kephas/ngx-core
Version:
Provides integration capabilities with Angular 13+.
1,207 lines (1,190 loc) • 44.2 kB
JavaScript
import * as i0 from '@angular/core';
import { ChangeDetectorRef, Component, ViewChildren, Input, forwardRef, Injectable, Injector, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { Logger, AppService, Priority, SingletonAppServiceContract, LogLevel, Injector as Injector$1, HashingService, EventHub } from '@kephas/core';
import { NotificationService } from '@kephas/ui';
import { __classPrivateFieldGet, __classPrivateFieldSet, __decorate, __metadata, __awaiter } from 'tslib';
import { BehaviorSubject, of } from 'rxjs';
import { map, finalize, catchError, retry } from 'rxjs/operators';
import * as i1 from '@angular/common/http';
import { HTTP_INTERCEPTORS, HttpClient, HttpHandler, HttpBackend, HttpXhrBackend } from '@angular/common/http';
import { CommandProcessorClient, CommandError } from '@kephas/commands';
import { MessageProcessorClient, MessagingError } from '@kephas/messaging';
import { XhrFactory } from '@angular/common';
import { TypeInfoRegistry } from '@kephas/reflection';
const NgTarget = 'ng';
/**
* Provides base functionality for a widget.
*
* @export
* @class WidgetBase
*/
class WidgetBase {
/**
* Creates an instance of WidgetBase.
* @param {ElementRef} elementRef The element reference.
* @param {ViewContainerRef} viewContainerRef The view container reference.
* @memberof WidgetBase
*/
constructor(elementRef, viewContainerRef) {
this.elementRef = elementRef;
this.viewContainerRef = viewContainerRef;
this._isVisible = true;
this._readonly = false;
const injector = viewContainerRef.injector;
this.logger = injector.get(Logger);
this.notification = injector.get(NotificationService);
this.changeDetector = injector.get(ChangeDetectorRef);
}
/**
* Gets or sets the child editors query.
*
* @readonly
* @type {QueryList<EditorBase<any>>}
* @memberof EditorBase
*/
get childWidgets() {
return this._childWidgets;
}
set childWidgets(value) {
if (this._childWidgets === value) {
return;
}
const oldValue = this._childWidgets;
this._childWidgets = value;
this.onChildWidgetsChanged(oldValue, value);
}
/**
* Gets or sets a value indicating whether the widget is visible.
*
* @readonly
* @type {boolean}
* @memberof WidgetBase
*/
get isVisible() {
return this._isVisible;
}
set isVisible(value) {
if (this._isVisible === value) {
return;
}
this._isVisible = value;
}
/**
* Gets or sets a value indicating whether the editor allows edits or not.
*
* @readonly
* @type {boolean}
* @memberof EditorBase
*/
get readonly() {
return this._readonly;
}
set readonly(value) {
if (this._readonly === value) {
return;
}
const oldValue = this._readonly;
this._readonly = value;
this.onReadOnlyChanged(oldValue, value);
}
/**
* A callback method that is invoked immediately after the
* default change detector has checked the directive's
* data-bound properties for the first time,
* and before any of the view or content children have been checked.
* It is invoked only once when the directive is instantiated.
*
* @memberof WidgetBase
*/
ngOnInit() {
}
/**
* A callback method that is invoked immediately after
* Angular has completed initialization of a component's view.
* It is invoked only once when the view is instantiated.
*
* @memberof WidgetBase
*/
ngAfterViewInit() {
}
/**
* A callback method that is invoked immediately after the
* default change detector has checked data-bound properties
* if at least one has changed, and before the view and content
* children are checked.
*
* @param changes The changed properties.
* @memberof WidgetBase
*/
ngOnChanges(changes) {
}
/**
* A callback method that performs custom clean-up, invoked immediately
* after a directive, pipe, or service instance is destroyed.
*/
ngOnDestroy() {
}
/**
* When overridden in a derived class, this method is called when the read only state changes.
*
* @protected
* @param {boolean} oldValue The old value.
* @param {boolean} newValue The new value.
*
* @memberof WidgetBase
*/
onReadOnlyChanged(oldValue, newValue) {
}
/**
* When overridden in a derived class, this method is called when the child widgets query changed.
*
* @protected
* @param {QueryList<EditorBase<any>>} oldValue The old query.
* @param {QueryList<EditorBase<any>>} newValue The new query.
*
* @memberof EditorBase
*/
onChildWidgetsChanged(oldValue, newValue) {
}
}
WidgetBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: WidgetBase, deps: [{ token: i0.ElementRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
WidgetBase.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.0", type: WidgetBase, selector: "ng-component", inputs: { isVisible: "isVisible", readonly: "readonly" }, viewQueries: [{ propertyName: "childWidgets", predicate: WidgetBase, descendants: true }], usesOnChanges: true, ngImport: i0, template: '', isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: WidgetBase, decorators: [{
type: Component,
args: [{
template: ''
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { childWidgets: [{
type: ViewChildren,
args: [WidgetBase]
}], isVisible: [{
type: Input
}], readonly: [{
type: Input
}] } });
/**
* This function provides the component as a WidgetBase,
* to be able to import it over this base class instead of over its own class.
*
* For example, use it as @ViewChild(WidgetBase) or @ViewChildren(WidgetBase).
*
* @export
* @param {Type<any>} componentType The component type.
* @returns {Provider} The provider.
*/
function provideWidget(componentType) {
return {
provide: WidgetBase,
useExisting: forwardRef(() => componentType)
};
}
/**
* This function provides the component as a NG_VALUE_ACCESSOR.
* Thus, it is possible to bind it like this:
* <my-component [(ngModel)]="boundProperty"></my-component>
*
* @export
* @param {Type<any>} componentType The component type.
* @returns {Provider} The provider.
*/
function provideValueAccessor(componentType) {
return {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => componentType),
multi: true
};
}
/**
* Provides a base implementation for value editors.
*
* @export
* @abstract
* @class ValueEditorBase
* @implements {OnInit}
* @implements {AfterViewInit}
* @implements {ControlValueAccessor}
* @template TValue The value type.
*/
class ValueEditorBase extends WidgetBase {
/**
* Creates an instance of ValueEditorBase.
*
* @param {ElementRef} elementRef The element reference.
* @param {ViewContainerRef} viewContainerRef The view container reference.
* @memberof ValueEditorBase
*/
constructor(elementRef, viewContainerRef) {
super(elementRef, viewContainerRef);
/**
* Gets or sets a value indicating whether the value is changed from the change event.
*
* @protected
* @memberof ValueEditorBase
*/
this.valueChangeFromEvent = false;
/**
* Gets or sets a value indicating whether the value is changed from the value property.
*
* @protected
* @memberof ValueEditorBase
*/
this.valueChangeFromValue = false;
this._onChange = (_) => {
// The implementation will get overwritten by Angular in RegisterOnChange.
};
this._onTouched = () => {
// The implementation will get overwritten by Angular in RegisterOnTouched.
};
}
/**
* Gets or sets the value to edit.
*
* @type {TValue}
* @memberOf ValueEditorBase
*/
get value() {
return this.getEditorValue();
}
set value(value) {
if (this._valueBeforeChange === value) {
return;
}
this.updateEditor(value);
}
/**
* Updates the underlying editor with the provided value.
*
* @protected
* @param {TValue} value
* @returns {boolean}
* @memberof ValueEditorBase
*/
updateEditor(value) {
if (this.valueChangeFromValue) {
return false;
}
const prevValueChangeFromValue = this.valueChangeFromValue;
this.valueChangeFromValue = true;
try {
const oldValue = this._valueBeforeChange;
this.onValueChanging(oldValue, value);
this._valueBeforeChange = value;
if (!this.valueChangeFromEvent) {
this.setEditorValue(value);
value = this.getEditorValue();
}
this.onValueChanged(oldValue, value);
}
catch (error) {
this.logger.error(error, 'Error while updating the editor.');
throw error;
}
finally {
this.valueChangeFromValue = prevValueChangeFromValue;
}
return true;
}
/**
* Overridable method invoked when the value is about to be changed.
*
* @protected
* @param {(TValue | undefined)} oldValue The old value.
* @param {(TValue | undefined)} newValue The new value.
* @memberof ValueEditorBase
*/
onValueChanging(oldValue, newValue) {
}
/**
* Overridable method invoked after the value was changed.
*
* @protected
* @param {(TValue | undefined)} oldValue The old value.
* @param {(TValue | undefined)} newValue The new value.
* @memberof ValueEditorBase
*/
onValueChanged(oldValue, newValue) {
this._onChange(newValue);
}
/**
* Callback invoked from the change event of the underlying editor.
*
* @protected
* @param {*} e
* @returns
* @memberof PropertyEditorComponent
*/
onEditorChange(e) {
if (this.valueChangeFromValue) {
return;
}
const prevValueChangeFromEvent = this.valueChangeFromEvent;
this.valueChangeFromEvent = true;
try {
const newValue = this.getEditorValueOnChange(e);
this.value = newValue;
}
catch (error) {
this.notification.notifyError(error);
}
finally {
this.valueChangeFromEvent = prevValueChangeFromEvent;
}
}
/**
* Gets the underlying editor's value upon change.
*
* @protected
* @param {*} e The change event arguments.
* @returns {TValue} The widget value.
* @memberof ValueEditorBase
*/
getEditorValueOnChange(e) {
return this.getEditorValue();
}
/**
* Write a new value to the element.
*
* @param {*} obj The new value.
*
* @memberOf PropertyEditorComponent
*/
writeValue(obj) {
this.value = obj;
}
/**
* Set the function to be called when the control receives a change event.
*
* @param {*} fn The callback function.
*
* @memberOf PropertyEditorComponent
*/
registerOnChange(fn) {
this._onChange = fn;
}
/**
* Set the function to be called when the control receives a touch event.
*
* @param {*} fn The callback function.
*
* @memberOf PropertyEditorComponent
*/
registerOnTouched(fn) {
this._onTouched = fn;
}
/**
* This function is called when the control status changes to or from "DISABLED".
* Depending on the value, it will enable or disable the appropriate DOM element.
*
* @param {boolean} isDisabled True if the state is disabled.
*
* @memberOf PropertyEditorComponent
*/
setDisabledState(isDisabled) {
}
}
ValueEditorBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: ValueEditorBase, deps: [{ token: i0.ElementRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
ValueEditorBase.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.0", type: ValueEditorBase, selector: "ng-component", inputs: { value: "value" }, usesInheritance: true, ngImport: i0, template: '', isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: ValueEditorBase, decorators: [{
type: Component,
args: [{
template: ''
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { value: [{
type: Input
}] } });
var _CommandQuery_loading, _CommandQuery_lastError;
/**
* Observable based on a command query.
*
* @export
* @abstract
* @class CommandQuery
* @extends {BehaviorSubject<TValue>}
* @template TArgs
* @template TResponseMessage
* @template TValue
*/
class CommandQuery extends BehaviorSubject {
/**
* Creates an instance of CommandQuery.
* @param {CommandProcessorClient} processor
* @param {string} command
* @param {(r: TResponseMessage, state?: CommandState<TArgs>) => TValue} [resultMap]
* @param {(args?: TArgs, state?: CommandState<TArgs>) => TArgs} [argsMap]
* @param {TValue} [emptyResult={} as TValue]
* @memberof CommandQuery
*/
constructor(processor, command, resultMap, argsMap, emptyResult = {}) {
var _a;
super(null);
this.processor = processor;
this.command = command;
this.resultMap = resultMap;
this.argsMap = argsMap;
this.emptyResult = emptyResult;
_CommandQuery_loading.set(this, false);
_CommandQuery_lastError.set(this, void 0);
(_a = this.args) !== null && _a !== void 0 ? _a : (this.args = {});
}
/**
* Gets a value indicating whether the query is executing.
*
* @readonly
* @type {boolean}
* @memberof CommandQuery
*/
get loading() {
return __classPrivateFieldGet(this, _CommandQuery_loading, "f");
}
/**
* Gets the last error executing this query.
*
* @readonly
* @type {*}
* @memberof CommandQuery
*/
get lastError() {
return __classPrivateFieldGet(this, _CommandQuery_lastError, "f");
}
/**
* Executes the command asynchronously.
*
* @param {CommandState<TArgs>} [state]
* @memberof CommandQuery
*/
execute(state) {
var _a, _b;
// no need to unsubscribe, as this is an auto-complete observable.
this.fetch((_a = state === null || state === void 0 ? void 0 : state.command) !== null && _a !== void 0 ? _a : this.command, (_b = state === null || state === void 0 ? void 0 : state.args) !== null && _b !== void 0 ? _b : this.args, state)
.subscribe(x => super.next(x));
}
fetch(command, args, state) {
__classPrivateFieldSet(this, _CommandQuery_loading, true, "f");
args = this.mapArgs(args, state);
return this.processor
.process(command, args)
.pipe(map(response => {
__classPrivateFieldSet(this, _CommandQuery_lastError, undefined, "f");
return this.mapResponse(response, state);
}), finalize(() => __classPrivateFieldSet(this, _CommandQuery_loading, false, "f")), catchError(err => {
__classPrivateFieldSet(this, _CommandQuery_lastError, err, "f");
return of(this.emptyResult);
}));
}
mapResponse(response, state) {
return this.resultMap ? this.resultMap(response, state) : response;
}
mapArgs(args, state) {
return this.argsMap ? this.argsMap(args, state) : args;
}
}
_CommandQuery_loading = new WeakMap(), _CommandQuery_lastError = new WeakMap();
var _MessageQuery_loading, _MessageQuery_lastError;
/**
* Observable based on a message query.
*
* @export
* @abstract
* @class MessageQuery
* @extends {BehaviorSubject<TValue>}
* @template TMessage
* @template TResponseMessage
* @template TValue
*/
class MessageQuery extends BehaviorSubject {
/**
* Creates an instance of MessageQuery.
* @param {MessageProcessorClient} processor
* @param {(r: TResponseMessage, state?: MessageState<TMessage>) => TValue} [resultMap]
* @param {(m: TMessage, state?: MessageState<TMessage>) => TMessage} [messageMap]
* @param {TValue} [emptyResult={} as TValue]
* @memberof MessageQuery
*/
constructor(processor, resultMap, messageMap, emptyResult = {}) {
super(null);
this.processor = processor;
this.resultMap = resultMap;
this.messageMap = messageMap;
this.emptyResult = emptyResult;
_MessageQuery_loading.set(this, false);
_MessageQuery_lastError.set(this, void 0);
}
/**
* Gets a value indicating whether the query is executing.
*
* @readonly
* @type {boolean}
* @memberof CommandQuery
*/
get loading() {
return __classPrivateFieldGet(this, _MessageQuery_loading, "f");
}
/**
* Gets the last error executing this query.
*
* @readonly
* @type {*}
* @memberof CommandQuery
*/
get lastError() {
return __classPrivateFieldGet(this, _MessageQuery_lastError, "f");
}
execute(state) {
// no need to unsubscribe, as this is an auto-complete observable.
this.fetch(state === null || state === void 0 ? void 0 : state.message, state)
.subscribe(x => super.next(x));
}
fetch(message, state) {
__classPrivateFieldSet(this, _MessageQuery_loading, true, "f");
message = this.mapMessage(message, state);
return this.processor
.process(message)
.pipe(map(response => {
__classPrivateFieldSet(this, _MessageQuery_lastError, undefined, "f");
return this.mapResponse(response, state);
}), finalize(() => __classPrivateFieldSet(this, _MessageQuery_loading, false, "f")), catchError(err => {
__classPrivateFieldSet(this, _MessageQuery_lastError, err, "f");
return of(this.emptyResult);
}));
}
mapResponse(response, state) {
return this.resultMap ? this.resultMap(response, state) : response;
}
mapMessage(message, state) {
return this.messageMap ? this.messageMap(message, state) : message;
}
}
_MessageQuery_loading = new WeakMap(), _MessageQuery_lastError = new WeakMap();
/**
* Browser implementation for an `XhrFactory`.
*
* @export
* @class BrowserXhrFactory
* @implements {XhrFactory}
*/
class BrowserXhrFactory {
build() {
return new XMLHttpRequest();
}
}
/**
* `HttpHandler` which applies an `HttpInterceptor` to an `HttpRequest`.
*
*/
class HttpInterceptorForwarder {
constructor(next, interceptor) {
this.next = next;
this.interceptor = interceptor;
}
handle(req) {
return this.interceptor.intercept(req, this.next);
}
}
/**
* An injectable `HttpHandler` that applies multiple interceptors
* to a request before passing it to the given `HttpBackend`.
*
* The interceptors are loaded lazily from the injector, to allow
* interceptors to themselves inject classes depending indirectly
* on `HttpInterceptingHandler` itself.
* @see `HttpInterceptor`
*/
class HttpInterceptingHandler {
/**
* Creates an instance of HttpInterceptingHandler.
* @param {HttpBackend} backend
* @param {Injector} injector
* @memberof HttpInterceptingHandler
*/
constructor(backend, injector) {
this.backend = backend;
this.injector = injector;
this.chain = null;
}
handle(req) {
if (this.chain === null) {
const interceptors = this.injector.get(HTTP_INTERCEPTORS, []);
this.chain = interceptors.reduceRight((next, interceptor) => new HttpInterceptorForwarder(next, interceptor), this.backend);
}
return this.chain.handle(req);
}
}
HttpInterceptingHandler.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: HttpInterceptingHandler, deps: [{ token: i1.HttpBackend }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
HttpInterceptingHandler.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: HttpInterceptingHandler });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: HttpInterceptingHandler, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: i1.HttpBackend }, { type: i0.Injector }]; } });
/**
* Gets the application settings.
*
* @export
* @class AppSettings
*/
let AppSettings = class AppSettings {
/**
* Gets the base URL of the application.
*
* @readonly
* @type {string}
* @memberof AppSettings
*/
get baseUrl() {
const baseQuery = document.getElementsByTagName('base');
const baseElement = baseQuery && baseQuery[0];
return (baseElement && baseElement.href) || document.baseURI || '/';
}
/**
* Gets the base API URL of the application.
*
* @readonly
* @type {string}
* @memberof AppSettings
*/
get baseApiUrl() {
return `${this.baseUrl}api/`;
}
};
AppSettings = __decorate([
AppService({ overridePriority: Priority.Low }),
SingletonAppServiceContract()
], AppSettings);
/**
* Provides proxied command execution over HTTP.
*
* @export
* @class HttpCommandProcessorClient
*/
let HttpCommandProcessorClient = class HttpCommandProcessorClient extends CommandProcessorClient {
/**
* Initializes a new instance of the CommandProcessor class.
* @param {NotificationService} notification The notification service.
* @param {HttpClient} http The HTTP client.
* @param {AppSettings} appSettings The application settings.
*/
constructor(appSettings, http, notification, logger) {
super();
this.appSettings = appSettings;
this.http = http;
this.notification = notification;
this.logger = logger;
/**
* Gets or sets the base route for the command execution.
*
* @protected
* @type {string}
* @memberof CommandProcessor
*/
this.baseRoute = 'api/cmd/';
}
/**
* Processes the command asynchronously.
* @tparam T The command response type.
* @param {string} command The command.
* @param {{}} [args] Optional. The arguments.
* @param {CommandClientContext} [options] Optional. Options controlling the command processing.
* @returns {Observable{T}} An observable over the result.
*/
process(command, args, options) {
const url = this.getHttpGetUrl(command, args, options);
let obs = this.http.get(url, this.getHttpGetOptions(command, args, options));
if (options && options.retries) {
obs = obs.pipe(retry(options.retries), map(response => this._processResponse(response, options)), catchError(error => this._processError(error, options)));
}
else {
obs = obs.pipe(map(response => this._processResponse(response, options)), catchError(error => this._processError(error, options)));
}
return obs;
}
/**
* Gets the HTTP GET URL.
*
* @protected
* @param {string} command The command.
* @param {{}} [args] Optional. The arguments.
* @param {CommandClientContext} [options] Optional. Options controlling the command processing.
* @returns {string} The HTTP GET URL.
* @memberof CommandProcessor
*/
getHttpGetUrl(command, args, options) {
let baseUrl = this.appSettings.baseUrl;
if (!baseUrl.endsWith('/')) {
baseUrl = baseUrl + '/';
}
return `${baseUrl}${this.baseRoute}${command}`;
}
/**
* Gets the command GET parameters.
*
* @protected
* @param {{}} [args]
* @param {CommandClientContext} [options]
* @return {*} {HttpParams}
* @memberof HttpCommandProcessorClient
*/
getHttpGetParams(args, options) {
let params = {};
if (args) {
Object.keys(args)
.forEach(key => params[key] = this._getParamValue(args[key]));
}
return params;
}
/**
* Gets the HTTP GET options. By default it does not return any options.
*
* @protected
* @param {string} command The command.
* @param {{}} [args] Optional. The arguments.
* @param {CommandClientContext} [options] Optional. Options controlling the command processing.
* @returns {({
* headers?: HttpHeaders | {
* [header: string]: string | string[];
* };
* observe?: 'body';
* params?: HttpParams | {
* [param: string]: string | string[];
* };
* reportProgress?: boolean;
* responseType?: 'json';
* withCredentials?: boolean;
* } | undefined)} The options or undefined.
* @memberof CommandProcessor
*/
getHttpGetOptions(command, args, options) {
return {
params: this.getHttpGetParams(args, options),
};
}
_processResponse(response, options) {
if (typeof response.severity === 'string') {
response.severity = LogLevel[response.severity];
}
if (response.severity <= LogLevel.Error) {
throw new CommandError(response.message, response);
}
if (response.severity === LogLevel.Warning) {
this.logger.log(response.severity, null, response.message);
if (!(options && (options.notifyWarnings === undefined || options.notifyWarnings))) {
this.notification.notifyWarning(response);
}
}
if (response.severity <= LogLevel.Error) {
throw new Error(response.message);
}
return response;
}
_processError(error, options) {
this.logger.error(error);
if (!(options && (options.notifyErrors === undefined || options.notifyErrors))) {
this.notification.notifyError(error);
}
throw error;
}
_getParamValue(rawValue) {
if (typeof rawValue === 'string') {
return rawValue;
}
if (Array.isArray(rawValue)) {
return rawValue.map(e => `${e}`);
}
return `${rawValue}`;
}
};
HttpCommandProcessorClient = __decorate([
AppService({ overridePriority: Priority.Low }),
__metadata("design:paramtypes", [AppSettings,
HttpClient,
NotificationService,
Logger])
], HttpCommandProcessorClient);
/**
* Provides proxied message processing over HTTP.
*
* @export
* @class MessageProcessor
*/
let HttpMessageProcessorClient = class HttpMessageProcessorClient extends MessageProcessorClient {
/**
* Initializes a new instance of the HttpMessageProcessor class.
* @param {NotificationService} notification The notification service.
* @param {HttpClient} http The HTTP client.
* @param {AppSettings} appSettings The application settings.
*/
constructor(appSettings, http, notification, logger) {
super();
this.appSettings = appSettings;
this.http = http;
this.notification = notification;
this.logger = logger;
/**
* Gets or sets the base route for the command execution.
*
* @protected
* @type {string}
* @memberof MessageProcessor
*/
this.baseRoute = 'api/msg/';
}
/**
* Processes the message asynchronously.
* @tparam T The message response type.
* @param {{}} message The message.
* @param {MessagingClientContext} [options] Optional. Options controlling the message processing.
* @returns {Observable{T}} An observable over the result.
*/
process(message, options) {
const url = this.getHttpPostUrl(message, options);
const obs = this.http.post(url, message, this.getHttpPostOptions(message, options));
const responseObj = (options && options.retries)
? obs.pipe(retry(options.retries), map(response => this._processResponse(response, options)), catchError(error => this._processError(error, options)))
: obs.pipe(map(response => this._processResponse(response, options)), catchError(error => this._processError(error, options)));
return responseObj;
}
/**
* Gets the HTTP GET URL.
*
* @protected
* @param {{}} message The message.
* @param {MessagingClientContext} [options] Optional. Options controlling the command processing.
* @returns {string} The HTTP GET URL.
* @memberof MessageProcessor
*/
getHttpPostUrl(message, options) {
let baseUrl = this.appSettings.baseUrl;
if (!baseUrl.endsWith('/')) {
baseUrl = baseUrl + '/';
}
const url = `${baseUrl}${this.baseRoute}`;
return url;
}
/**
* Gets the HTTP GET options. By default it does not return any options.
*
* @protected
* @param {string} command The command.
* @param {{}} [args] Optional. The arguments.
* @param {MessagingClientContext} [options] Optional. Options controlling the command processing.
* @returns {({
* headers?: HttpHeaders | {
* [header: string]: string | string[];
* };
* observe?: 'body';
* params?: HttpParams | {
* [param: string]: string | string[];
* };
* reportProgress?: boolean;
* responseType?: 'json';
* withCredentials?: boolean;
* } | undefined)} The options or undefined.
* @memberof MessageProcessor
*/
getHttpPostOptions(message, options) {
return undefined;
}
_processResponse(rawResponse, options) {
if (rawResponse.exception) {
const errorInfo = rawResponse.exception;
if (typeof errorInfo.severity === 'string') {
errorInfo.severity = LogLevel[errorInfo.severity];
}
throw new MessagingError(errorInfo.message, errorInfo);
}
const response = rawResponse.message;
if (typeof response.severity === 'string') {
response.severity = LogLevel[response.severity];
}
if (!response.severity) {
response.severity = LogLevel.Info;
}
if (response.severity <= LogLevel.Error) {
throw new MessagingError(response.message, response);
}
if (response.severity === LogLevel.Warning) {
this.logger.log(response.severity, null, response.message);
if (!(options && (options.notifyWarnings === undefined || options.notifyWarnings))) {
this.notification.notifyWarning(response);
}
}
if (response.severity <= LogLevel.Error) {
throw new MessagingError(response.message, response);
}
return response;
}
_processError(error, options) {
this.logger.error(error);
if (!(options && (options.notifyErrors === undefined || options.notifyErrors))) {
this.notification.notifyError(error);
}
throw error;
}
};
HttpMessageProcessorClient = __decorate([
AppService({ overridePriority: Priority.Low }),
__metadata("design:paramtypes", [AppSettings,
HttpClient,
NotificationService,
Logger])
], HttpMessageProcessorClient);
var Configuration_1;
// https://stackoverflow.com/questions/50222998/error-encountered-in-metadata-generated-for-exported-symbol-when-constructing-an
// @dynamic
/**
* The configuration service.
*
* @export
* @class Configuration
* @implements {AsyncInitializable}
*/
let Configuration = Configuration_1 = class Configuration {
/**
* Ensures that the configuration file is initialized.
*
* @param {{ http: HttpClient, configurationFileUrl?: string }} context The context containing initialization data.
* @returns {Promise<void>}
* @memberof Configuration
*/
initializeAsync(context) {
return __awaiter(this, void 0, void 0, function* () {
if (Configuration_1.configurationFile) {
return;
}
const response = yield context.http.get(context.configurationFileUrl ? context.configurationFileUrl : Configuration_1.configurationFileUrl).toPromise();
Configuration_1.configurationFile = response || {};
});
}
/**
* Gets the configuration settings for the indicated section name.
*
* @template T The settings type.
* @param {string} sectionName The section name.
* @returns {T} The settings.
* @memberof Configuration
*/
getSettings(settingsType) {
if (!Configuration_1.configurationFile) {
throw new Error('The configuration manager must be initialized prior to requesting settings from it.');
}
let sectionName = settingsType.name;
const ending = 'Settings';
if (sectionName.endsWith(ending)) {
sectionName = sectionName.substring(0, sectionName.length - ending.length);
}
sectionName = sectionName[0].toLowerCase() + sectionName.substring(1);
return Configuration_1.configurationFile[sectionName];
}
};
Configuration.configurationFileUrl = '/app/configuration.json';
Configuration = Configuration_1 = __decorate([
AppService({ overridePriority: Priority.Low }),
SingletonAppServiceContract()
], Configuration);
var _a, _RootProvidersRegistry_providers;
/**
* Registry for root services.
*
* @export
* @class RootProvidersRegistry
*/
class RootProvidersRegistry {
/**
* Gets the providers for the HTTP client.
*
* @returns {((StaticClassProvider | ExistingProvider)[])}
* @memberof HttpClientAppServiceInfoRegistry
*/
static getRootProviders(serviceRegistry) {
const providers = [];
for (const c of serviceRegistry.serviceContracts) {
const serviceContract = c;
if (c.target === NgTarget) {
Injectable()(serviceContract.contractType);
for (const m of serviceContract.services) {
const serviceMetadata = m;
Injectable()(serviceMetadata.serviceType);
providers.push({
provide: serviceContract.contractToken || serviceContract.contractType,
useClass: serviceMetadata.serviceType,
multi: serviceContract.allowMultiple,
deps: RootProvidersRegistry.getDependencies(serviceMetadata.serviceType),
});
}
}
}
providers.push(...__classPrivateFieldGet(RootProvidersRegistry, _a, "f", _RootProvidersRegistry_providers));
return providers;
}
/**
* Loads asynchronously the modules to make sure that the
* overridden services area also loaded into the service registry.
* First of all, loads the Kephas modules, afterwards
* loads the application modules invoking the provided delegate.
*/
static loadModules(loadAppModules) {
return __awaiter(this, void 0, void 0, function* () {
yield import('@kephas/core');
yield import('@kephas/reflection');
yield import('@kephas/commands');
yield import('@kephas/messaging');
yield import('@kephas/ui');
yield import('@angular/common/http');
if (loadAppModules) {
yield loadAppModules();
}
});
}
static getDependencies(serviceType) {
let deps = Reflect.getMetadata('design:paramtypes', serviceType);
if (!deps && serviceType.ctorParameters) {
deps = serviceType.ctorParameters();
}
return deps || [];
}
}
_a = RootProvidersRegistry;
_RootProvidersRegistry_providers = { value: [
{ provide: HttpClient, useClass: HttpClient, deps: [HttpHandler] },
{ provide: HttpHandler, useClass: HttpInterceptingHandler, deps: [HttpBackend, Injector] },
{ provide: HttpBackend, useClass: HttpXhrBackend, deps: [XhrFactory] },
{ provide: HttpXhrBackend, useClass: HttpXhrBackend, deps: [XhrFactory] },
{ provide: XhrFactory, useClass: BrowserXhrFactory, deps: [] },
] };
function resolveAppService(type) {
Injectable()(type);
return (injector) => Injector$1.instance.resolve(type, t => injector.get(t));
}
class KephasModule {
}
KephasModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: KephasModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
KephasModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: KephasModule });
KephasModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: KephasModule, providers: [
// core
{
provide: Injector$1,
useFactory: resolveAppService(Injector$1),
deps: [Injector]
},
{
provide: Logger,
useFactory: resolveAppService(Logger),
deps: [Injector]
},
{
provide: HashingService,
useFactory: resolveAppService(HashingService),
deps: [Injector]
},
{
provide: EventHub,
useFactory: resolveAppService(EventHub),
deps: [Injector]
},
// commands
{
provide: CommandProcessorClient,
useFactory: resolveAppService(CommandProcessorClient),
deps: [Injector]
},
// messaging
{
provide: MessageProcessorClient,
useFactory: resolveAppService(MessageProcessorClient),
deps: [Injector]
},
// reflection
{
provide: TypeInfoRegistry,
useFactory: resolveAppService(TypeInfoRegistry),
deps: [Injector]
},
// ui
{
provide: NotificationService,
useFactory: resolveAppService(NotificationService),
deps: [Injector]
},
// ngx-core
{
provide: AppSettings,
useFactory: resolveAppService(AppSettings),
deps: [Injector]
},
{
provide: Configuration,
useFactory: resolveAppService(Configuration),
deps: [Injector]
},
HttpInterceptingHandler,
] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: KephasModule, decorators: [{
type: NgModule,
args: [{
providers: [
// core
{
provide: Injector$1,
useFactory: resolveAppService(Injector$1),
deps: [Injector]
},
{
provide: Logger,
useFactory: resolveAppService(Logger),
deps: [Injector]
},
{
provide: HashingService,
useFactory: resolveAppService(HashingService),
deps: [Injector]
},
{
provide: EventHub,
useFactory: resolveAppService(EventHub),
deps: [Injector]
},
// commands
{
provide: CommandProcessorClient,
useFactory: resolveAppService(CommandProcessorClient),
deps: [Injector]
},
// messaging
{
provide: MessageProcessorClient,
useFactory: resolveAppService(MessageProcessorClient),
deps: [Injector]
},
// reflection
{
provide: TypeInfoRegistry,
useFactory: resolveAppService(TypeInfoRegistry),
deps: [Injector]
},
// ui
{
provide: NotificationService,
useFactory: resolveAppService(NotificationService),
deps: [Injector]
},
// ngx-core
{
provide: AppSettings,
useFactory: resolveAppService(AppSettings),
deps: [Injector]
},
{
provide: Configuration,
useFactory: resolveAppService(Configuration),
deps: [Injector]
},
HttpInterceptingHandler,
]
}]
}] });
/*
* Public API Surface of @kephas/angular
*/
/**
* Generated bundle index. Do not edit.
*/
export { AppSettings, BrowserXhrFactory, CommandQuery, Configuration, HttpCommandProcessorClient, HttpInterceptingHandler, HttpInterceptorForwarder, HttpMessageProcessorClient, KephasModule, MessageQuery, NgTarget, RootProvidersRegistry, ValueEditorBase, WidgetBase, provideValueAccessor, provideWidget, resolveAppService };
//# sourceMappingURL=kephas-ngx-core.mjs.map