wacom
Version:
Module which has common services, pipes, directives and interfaces which can be used on all projects.
1,273 lines (1,254 loc) • 84.4 kB
TypeScript
import * as i0 from '@angular/core';
import { WritableSignal, Signal, InjectionToken, EnvironmentProviders, PipeTransform, ComponentRef, Type, ModuleWithProviders } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpErrorResponse, HttpClient } from '@angular/common/http';
import { Router, ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router';
import * as _angular_platform_browser from '@angular/platform-browser';
import { Meta, Title } from '@angular/platform-browser';
import * as i1 from '@angular/common';
import { DatePipe } from '@angular/common';
import * as i2 from '@angular/forms';
declare global {
interface String {
capitalize(): string;
}
}
type Viewport = 'mobile' | 'tablet' | 'desktop';
declare class CoreService {
private readonly _platformId;
private readonly _isBrowser;
private readonly _destroyRef;
deviceID: string;
constructor();
/**
* Generates a UUID (Universally Unique Identifier) version 4.
*
* This implementation uses `Math.random()` to generate random values,
* making it suitable for general-purpose identifiers, but **not** for
* cryptographic or security-sensitive use cases.
*
* The format follows the UUID v4 standard: `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`
* where:
* - `x` is a random hexadecimal digit (0–f)
* - `4` indicates UUID version 4
* - `y` is one of 8, 9, A, or B
*
* Example: `f47ac10b-58cc-4372-a567-0e02b2c3d479`
*
* @returns A string containing a UUID v4.
*/
UUID(): string;
/**
* Converts an object to an array. Optionally holds keys instead of values.
*
* @param {any} obj - The object to be converted.
* @param {boolean} [holder=false] - If true, the keys will be held in the array; otherwise, the values will be held.
* @returns {any[]} The resulting array.
*/
ota(obj: any, holder?: boolean): any[];
/**
* Removes elements from `fromArray` that are present in `removeArray` based on a comparison field.
*
* @param {any[]} removeArray - The array of elements to remove.
* @param {any[]} fromArray - The array from which to remove elements.
* @param {string} [compareField='_id'] - The field to use for comparison.
* @returns {any[]} The modified `fromArray` with elements removed.
*/
splice(removeArray: any[], fromArray: any[], compareField?: string): any[];
/**
* Unites multiple _id values into a single unique _id.
* The resulting _id is unique regardless of the order of the input _id values.
*
* @param {...string[]} args - The _id values to be united.
* @returns {string} The unique combined _id.
*/
ids2id(...args: string[]): string;
private _afterWhile;
/**
* Delays the execution of a callback function for a specified amount of time.
* If called again within that time, the timer resets.
*
* @param {string | object | (() => void)} doc - A unique identifier for the timer, an object to host the timer, or the callback function.
* @param {() => void} [cb] - The callback function to execute after the delay.
* @param {number} [time=1000] - The delay time in milliseconds.
*/
afterWhile(doc: string | object | (() => void), cb?: () => void, time?: number): void;
/**
* Recursively copies properties from one object to another.
* Handles nested objects, arrays, and Date instances appropriately.
*
* @param from - The source object from which properties are copied.
* @param to - The target object to which properties are copied.
*/
copy(from: any, to: any): void;
device: string;
/**
* Detects the device type based on the user agent.
*/
detectDevice(): void;
/**
* Checks if the device is a mobile device.
* @returns {boolean} - Returns true if the device is a mobile device.
*/
isMobile(): boolean;
/**
* Checks if the device is a tablet.
* @returns {boolean} - Returns true if the device is a tablet.
*/
isTablet(): boolean;
/**
* Checks if the device is a web browser.
* @returns {boolean} - Returns true if the device is a web browser.
*/
isWeb(): boolean;
/**
* Checks if the device is an Android device.
* @returns {boolean} - Returns true if the device is an Android device.
*/
isAndroid(): boolean;
/**
* Checks if the device is an iOS device.
* @returns {boolean} - Returns true if the device is an iOS device.
*/
isIos(): boolean;
readonly viewport: WritableSignal<Viewport>;
readonly isViewportMobile: Signal<boolean>;
readonly isViewportTablet: Signal<boolean>;
readonly isViewportDesktop: Signal<boolean>;
detectViewport(): void;
version: string;
appVersion: string;
dateVersion: string;
/**
* Sets the combined version string based on appVersion and dateVersion.
*/
setVersion(): void;
/**
* Sets the app version and updates the combined version string.
*
* @param {string} appVersion - The application version to set.
*/
setAppVersion(appVersion: string): void;
/**
* Sets the date version and updates the combined version string.
*
* @param {string} dateVersion - The date version to set.
*/
setDateVersion(dateVersion: string): void;
private _locked;
private _unlockResolvers;
/**
* Locks a resource to prevent concurrent access.
* @param which - The resource to lock, identified by a string.
*/
lock(which: string): void;
/**
* Unlocks a resource, allowing access.
* @param which - The resource to unlock, identified by a string.
*/
unlock(which: string): void;
/**
* Returns a Promise that resolves when the specified resource is unlocked.
* @param which - The resource to watch for unlocking, identified by a string.
* @returns A Promise that resolves when the resource is unlocked.
*/
onUnlock(which: string): Promise<void>;
/**
* Checks if a resource is locked.
* @param which - The resource to check, identified by a string.
* @returns True if the resource is locked, false otherwise.
*/
locked(which: string): boolean;
/**
* Converts a plain object into a signal-wrapped object.
* Optionally wraps specific fields of the object as individual signals,
* and merges them into the returned signal for fine-grained reactivity.
*
* @template Document - The type of the object being wrapped.
* @param {Document} document - The plain object to wrap into a signal.
* @param {Record<string, (doc: Document) => unknown>} [signalFields={}] -
* Optional map where each key is a field name and the value is a function
* to extract the initial value for that field. These fields will be wrapped
* as separate signals and embedded in the returned object.
*
* @returns {WritableSignal<Document>} A signal-wrapped object, possibly containing
* nested field signals for more granular control.
*
* @example
* const user = { _id: '1', name: 'Alice', score: 42 };
* const sig = toSignal(user, { score: (u) => u.score });
* console.log(sig().name); // 'Alice'
* console.log(sig().score()); // 42 — field is now a signal
*/
toSignal<Document>(document: Document, signalFields?: Record<string, (doc: Document) => unknown>): WritableSignal<Document>;
/**
* Converts an array of objects into an array of Angular signals.
* Optionally wraps specific fields of each object as individual signals.
*
* @template Document - The type of each object in the array.
* @param {Document[]} arr - Array of plain objects to convert into signals.
* @param {Record<string, (doc: Document) => unknown>} [signalFields={}] -
* Optional map where keys are field names and values are functions that extract the initial value
* from the object. These fields will be turned into separate signals.
*
* @returns {WritableSignal<Document>[]} An array where each item is a signal-wrapped object,
* optionally with individual fields also wrapped in signals.
*
* @example
* toSignalsArray(users, {
* name: (u) => u.name,
* score: (u) => u.score,
* });
*/
toSignalsArray<Document>(arr: Document[], signalFields?: Record<string, (doc: Document) => unknown>): WritableSignal<Document>[];
/**
* Adds a new object to the signals array.
* Optionally wraps specific fields of the object as individual signals before wrapping the whole object.
*
* @template Document - The type of the object being added.
* @param {WritableSignal<Document>[]} signals - The signals array to append to.
* @param {Document} item - The object to wrap and push as a signal.
* @param {Record<string, (doc: Document) => unknown>} [signalFields={}] -
* Optional map of fields to be wrapped as signals within the object.
*
* @returns {void}
*/
pushSignal<Document>(signals: WritableSignal<Document>[], item: Document, signalFields?: Record<string, (doc: Document) => unknown>): void;
/**
* Removes the first signal from the array whose object's field matches the provided value.
* @template Document
* @param {WritableSignal<Document>[]} signals - The signals array to modify.
* @param {unknown} value - The value to match.
* @param {string} [field='_id'] - The object field to match against.
* @returns {void}
*/
removeSignalByField<Document extends Record<string, unknown>>(signals: WritableSignal<Document>[], value: unknown, field?: string): void;
/**
* Returns a generic trackBy function for *ngFor, tracking by the specified object field.
* @template Document
* @param {string} field - The object field to use for tracking (e.g., '_id').
* @returns {(index: number, sig: Signal<Document>) => unknown} TrackBy function for Angular.
*/
trackBySignalField<Document extends Record<string, unknown>>(field: string): (_: number, sig: Signal<Document>) => unknown;
/**
* Finds the first signal in the array whose object's field matches the provided value.
* @template Document
* @param {Signal<Document>[]} signals - Array of signals to search.
* @param {unknown} value - The value to match.
* @param {string} [field='_id'] - The object field to match against.
* @returns {Signal<Document> | undefined} The found signal or undefined if not found.
*/
findSignalByField<Document extends Record<string, unknown>>(signals: WritableSignal<Document>[], value: unknown, field?: string): WritableSignal<Document> | undefined;
/**
* Updates the first writable signal in the array whose object's field matches the provided value.
* @template Document
* @param {WritableSignal<Document>[]} signals - Array of writable signals to search.
* @param {unknown} value - The value to match.
* @param {(val: Document) => Document} updater - Function to produce the updated object.
* @param {string} field - The object field to match against.
* @returns {void}
*/
updateSignalByField<Document extends Record<string, unknown>>(signals: WritableSignal<Document>[], value: unknown, updater: (val: Document) => Document, field: string): void;
static ɵfac: i0.ɵɵFactoryDeclaration<CoreService, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<CoreService>;
}
/**
* Basic fields expected on a document managed by the CRUD service.
*/
interface CrudDocument<Document> {
/** Unique identifier of the document. */
_id?: string;
/** Temporary unique identifier of the document for offline use */
_localId?: number;
/** Optional application identifier to which the document belongs. */
appId?: string;
/** Numerical position used for manual ordering. */
order?: number;
/** Flag indicating the document is creating */
__creating?: boolean;
/** Flag set when the document has been modified locally. */
__modified?: string[];
/** Flag set when the document has been deleted locally. */
__deleted?: boolean;
__options?: Record<string, CrudOptions<Document>>;
}
/**
* Options that can be supplied to CRUD operations.
*/
interface CrudOptions<Document> {
/** Logical name of the collection or resource. */
name?: string;
/** Callback invoked with the server response. */
callback?: (resp: Document | Document[]) => void;
/** Callback invoked if the request fails. */
errCallback?: (resp: unknown) => void;
}
/**
* Contract implemented by services performing CRUD requests.
*/
interface CrudServiceInterface<Document> {
/** Retrieve a page of documents from the server. */
get: (params: {
page: number;
query?: string;
}, options: CrudOptions<Document>) => any;
/** Return the current in‑memory documents. */
getDocs: () => Document[];
/** Create a new document. */
create: (doc: Document) => any;
/** Update an existing document. */
update: (doc: Document) => any;
/** Delete the provided document. */
delete: (doc: Document) => any;
/** Change the number of documents retrieved per page. */
setPerPage?: (count: number) => void;
/** Resolves when the initial data load has completed. */
loaded: Observable<unknown>;
getSignal: (doc: string | Document) => any;
}
/**
* Configuration describing how a CRUD table should behave.
*/
interface TableConfigButton<Document> {
icon?: string;
click?: (doc: Document) => void;
hrefFunc?: (doc: Document) => string;
class?: string;
}
interface TableConfig<Document> {
/** Callback to paginate to a given page. */
paginate?: (page?: number) => void;
/** Number of documents shown per page. */
perPage?: number;
/** Function used to update the page size. */
setPerPage?: ((count: number) => void) | undefined;
/** When true, fetch all documents instead of paginating. */
allDocs?: boolean;
/** Handler invoked to create a new record. */
create: (() => void) | null;
/** Handler invoked to edit a record. */
update: ((doc: Document) => void) | null;
/** Handler invoked to delete a record. */
delete: ((doc: Document) => void) | null;
/** Row‑level action buttons. */
buttons: TableConfigButton<Document>[];
/** Buttons displayed in the table header. */
headerButtons: TableConfigButton<Document>[];
}
interface CrudConfig<Document> {
signalFields?: Record<string, (doc: Document) => unknown>;
name: string;
_id?: string;
replace?: (doc: Document) => void;
unauthorized?: boolean;
appId?: string;
}
interface GetConfig {
page?: number;
perPage?: number;
query?: string;
}
/**
* Abstract reusable base class for CRUD list views.
* It encapsulates pagination, modals, and document handling logic.
*
* @template Service - A service implementing CrudServiceInterface for a specific document type
* @template Document - The data model extending CrudDocument
*/
declare abstract class CrudComponent<Service extends CrudServiceInterface<Document>, Document extends CrudDocument<Document>, FormInterface> {
/** Service responsible for data fetching, creating, updating, deleting */
protected crudService: Service;
/** The array of documents currently loaded and shown */
protected documents: WritableSignal<Signal<Document>[]>;
/** Form schema/config used by the FormService modals */
protected form: FormInterface;
/** Current pagination page */
protected page: number;
/** CoreService handles timing and copying helpers */
private __core;
/** ChangeDetectorRef handles on push strategy */
private __cdr;
/** Internal reference to form service matching FormServiceInterface */
private __formService;
/**
* Constructor
*
* @param formConfig - Object describing form title and its component structure
* @param formService - Any service that conforms to FormServiceInterface (usually casted)
* @param crudService - CRUD service implementing get/create/update/delete
*/
constructor(formConfig: unknown, formService: unknown, crudService: Service, module?: string);
protected localDocumentsFilter: (doc: Document) => boolean;
/**
* Allow set query customization
*/
protected setDocumentsQuery(query: string): string;
/**
* Loads documents for a given page.
*/
protected setDocuments(page?: number, query?: string): Promise<void>;
/** Fields considered when performing bulk updates. */
protected updatableFields: string[];
/**
* Clears temporary metadata before document creation.
*/
protected preCreate(doc: Document): void;
/**
* Funciton which controls whether the create functionality is available.
*/
protected allowCreate(): boolean;
/**
* Funciton which controls whether the update and delete functionality is available.
*/
protected allowMutate(): boolean;
/**
* Funciton which controls whether the unique url functionality is available.
*/
protected allowUrl(): boolean;
/** Determines whether manual sorting controls are available. */
protected allowSort(): boolean;
/**
* Funciton which prepare get crud options.
*/
protected getOptions(): CrudOptions<Document>;
/**
* Handles bulk creation and updating of documents.
* In creation mode, adds new documents.
* In update mode, syncs changes and deletes removed entries.
*/
protected bulkManagement(isCreateFlow?: boolean): () => void;
/** Opens a modal to create a new document. */
protected create(): void;
/** Displays a modal to edit an existing document. */
protected update(doc: Document): void;
/** Requests confirmation before deleting the provided document. */
protected delete(doc: Document): Promise<void>;
/** Opens a modal to edit the document's unique URL. */
protected mutateUrl(doc: Document): void;
/** Moves the given document one position up and updates ordering. */
protected moveUp(doc: Document): void;
/** Data source mode used for document retrieval. */
protected configType: 'server' | 'local';
/** Number of documents fetched per page when paginating. */
protected perPage: number;
/**
* Configuration object used by the UI for rendering table and handling actions.
*/
protected getConfig(): TableConfig<Document>;
/** Name of the collection or module used for contextual actions. */
private _module;
}
type Any = unknown;
declare class EmitterService {
private _signals;
private _closers;
private _streams;
private _getSignal;
private _getCloser;
private _getStream;
/** Emit an event */
emit<T = Any>(id: string, data?: T): void;
/** Listen for events (hot, completes when off(id) is called) */
on<T = Any>(id: string): Observable<T>;
/** Complete and remove a channel */
off(id: string): void;
offAll(): void;
has(id: string): boolean;
private _done;
private _getDoneSignal;
/** Mark task as completed with a payload (default: true) */
complete<T = Any>(task: string, value?: T): void;
/** Clear completion so it can be awaited again */
clearCompleted(task: string): void;
/** Read current completion payload (undefined => not completed) */
completed(task: string): Any | undefined;
isCompleted(task: string): boolean;
onComplete(tasks: string | string[], opts?: {
mode?: 'all' | 'any';
timeoutMs?: number;
abort?: AbortSignal;
}): Observable<Any | Any[]>;
static ɵfac: i0.ɵɵFactoryDeclaration<EmitterService, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<EmitterService>;
}
/**
* High-level page metadata (route-driven or manual).
*
* Keep it simple:
* - title, description, image are the only "content" fields you set.
* - everything else (og/twitter/itemprop variants) is generated automatically.
* - links are managed separately via MetaService.setLink().
*/
interface MetaPage {
/** Document title (without suffix). */
title?: string;
/** Optional per-page suffix override (used only when useTitleSuffix = true). */
titleSuffix?: string;
/** Standard description (mirrored to OG/Twitter + itemprop). */
description?: string;
/** Absolute URL to image (mirrored to OG/Twitter + itemprop). */
image?: string;
/**
* Indexing flag.
* - index: true -> "index, follow" (unless robots is explicitly provided)
* - index: false -> "noindex, follow" (unless robots is explicitly provided)
*/
index?: boolean;
/**
* Explicit robots directive (takes precedence over index if provided).
* Example: "noindex, nofollow" or "index, follow, max-image-preview:large"
*/
robots?: string;
/**
* Disable any updates for this page.
* Useful for pages that fully manage meta themselves.
*/
disableUpdate?: boolean;
}
/**
* Defaults applied to every route/page, and used for reset().
*/
interface MetaDefaults extends MetaPage {
/**
* Default link tags (e.g. canonical).
* This is not auto-generated because canonical depends on domain + route policy.
*/
links?: Record<string, string>;
}
/**
* Options controlling behavior of the meta management.
*/
interface MetaConfig {
/**
* Whether to append configured titleSuffix to titles.
* - If true: title = (page.title ?? defaults.title) + (page.titleSuffix ?? defaults.titleSuffix)
* - If false: title = (page.title ?? defaults.title)
*/
useTitleSuffix?: boolean;
/**
* Automatically apply route meta on each NavigationEnd.
* Recommended: true (prevents "forgot MetaGuard" issues).
*/
applyFromRoutes?: boolean;
/** Default metadata applied to all routes/pages. */
defaults?: MetaDefaults;
}
/**
* Configuration for the storage abstraction used by the library.
*/
interface StoreConfig {
/** Key prefix applied to all stored values. */
prefix?: string;
/** Persist a value under the given field name. */
set?: (field: string, value: string | number, cb?: () => void, errCb?: (err: unknown) => void) => Promise<boolean>;
/** Retrieve a value by field name. */
get?: (field: string, cb?: (value: string) => void, errCb?: (err: unknown) => void) => Promise<string>;
/** Remove a stored value. */
remove?: (field: string, cb?: () => void, errCb?: (err: unknown) => void) => Promise<boolean>;
/** Clear all stored values created by the library. */
clear?: (cb?: () => void, errCb?: (err: unknown) => void) => Promise<boolean>;
}
interface StoreOptions<T = unknown> {
onSuccess?: (value?: T | null) => void;
onError?: (err: unknown) => void;
defaultValue?: T;
clearOnError?: boolean;
}
type HttpHeaderType = string | number | (string | number)[];
/**
* Configuration values used by the HTTP service when
* issuing requests to a backend API.
*/
interface HttpConfig {
/** Map of default headers appended to each request. */
headers?: Record<string, HttpHeaderType>;
/** Base URL for all HTTP requests. */
url?: string;
}
declare const DEFAULT_HTTP_CONFIG: HttpConfig;
type NetworkStatus = 'good' | 'poor' | 'none';
interface NetworkConfig {
/** Ordered list of endpoints to probe (first that succeeds wins). */
endpoints: string[];
/** Periodic re-check interval (ms). */
intervalMs: number;
/** Per-request timeout (ms). */
timeoutMs: number;
/** Latency threshold (ms) to classify as "good". */
goodLatencyMs: number;
/** Consecutive failures to flip status to "none". */
maxConsecutiveFails: number;
}
declare const DEFAULT_NETWORK_CONFIG: NetworkConfig;
declare const NETWORK_CONFIG: InjectionToken<NetworkConfig>;
/**
* Root configuration object used to initialize the library.
* Each property allows consumers to override the default
* behavior of the corresponding service.
*/
interface Config {
/** Options for the key‑value storage service. */
store?: StoreConfig;
/** Defaults applied to page metadata handling. */
meta?: MetaConfig;
/** Base HTTP settings such as API URL and headers. */
http?: HttpConfig;
/** Optional socket connection configuration. */
socket?: any;
/** Raw Socket.IO client instance, if used. */
io?: any;
network?: NetworkConfig;
}
declare const CONFIG_TOKEN: InjectionToken<Config>;
declare const DEFAULT_CONFIG: Config;
declare class HttpService {
private _http;
private readonly _isBrowser;
errors: ((err: HttpErrorResponse, retry?: () => void) => {})[];
url: string;
locked: boolean;
awaitLocked: ReturnType<typeof setTimeout>[];
private _config;
private _headers;
private _http_headers;
constructor(config: Config, _http: HttpClient);
setUrl(url: string): void;
removeUrl(): void;
set(key: any, value: any): void;
header(key: any): HttpHeaderType;
remove(key: any): void;
private _httpMethod;
/**
* Internal method to handle HTTP requests for various methods (POST, PUT, PATCH, DELETE, GET).
*
* Features:
* - **Request Locking**: Manages request locking to prevent simultaneous requests.
* - **Acceptance Check**: Validates the server response against a user-defined `acceptance` function.
* If the check fails, the response is rejected with an error.
* - **Replace Logic**: Allows modification of specific parts of the response object, determined by a user-defined `replace` function.
* Can handle both objects and arrays within the response.
* - **Field Filtering**: Supports extracting specific fields from response objects or arrays.
* - **Legacy Support**: Compatible with callback-based usage alongside Observables.
* - **ReplaySubject**: Ensures that the response can be shared across multiple subscribers.
*
* @param url - The endpoint to send the HTTP request to (relative to the base URL).
* @param doc - The request payload for methods like POST, PUT, and PATCH.
* @param callback - A legacy callback function to handle the response.
* @param opts - Additional options:
* - `err`: Error handling callback.
* - `acceptance`: Function to validate the server response. Should return `true` for valid responses.
* - `replace`: Function to modify specific parts of the response data.
* - `fields`: Array of fields to extract from the response object(s).
* - `data`: Path in the response where the data resides for `replace` and `fields` operations.
* - `skipLock`: If `true`, bypasses request locking.
* - `url`: Overrides the base URL for this request.
* @param method - The HTTP method (e.g., 'post', 'put', 'patch', 'delete', 'get').
* @returns An Observable that emits the processed HTTP response or an error.
*/
private _post;
/**
* Public method to perform a POST request.
* - Supports legacy callback usage.
* - Returns an Observable for reactive programming.
*/
post(url: string, doc: any, callback?: (resp: any) => void, opts?: any): Observable<any>;
/**
* Public method to perform a PUT request.
* - Supports legacy callback usage.
* - Returns an Observable for reactive programming.
*/
put(url: string, doc: any, callback?: (resp: any) => void, opts?: any): Observable<any>;
/**
* Public method to perform a PATCH request.
* - Supports legacy callback usage.
* - Returns an Observable for reactive programming.
*/
patch(url: string, doc: any, callback?: (resp: any) => void, opts?: any): Observable<any>;
/**
* Public method to perform a DELETE request.
* - Supports legacy callback usage.
* - Returns an Observable for reactive programming.
*/
delete(url: string, callback?: (resp: any) => void, opts?: any): Observable<any>;
/**
* Public method to perform a GET request.
* - Supports legacy callback usage.
* - Returns an Observable for reactive programming.
*/
get(url: string, callback?: (resp: any) => void, opts?: any): Observable<any>;
clearLocked(): void;
lock(): void;
unlock(): void;
/**
* Handles HTTP errors.
* - Calls provided error callback and retries the request if needed.
*/
private handleError;
/**
* Internal method to trigger error handling callbacks.
*/
private err_handle;
private prepare_handle;
private response_handle;
/**
* Retrieves a nested object or property from the response based on a dot-separated path.
*
* @param resp - The response object to retrieve data from.
* @param base - A dot-separated string indicating the path to the desired property within the response.
* - Example: `'data.items'` will navigate through `resp.data.items`.
* - If empty, the entire response is returned.
* @returns The object or property located at the specified path within the response.
*/
private _getObjectToReplace;
/**
* Sets or replaces a nested object or property in the response based on a dot-separated path.
*
* @param resp - The response object to modify.
* @param base - A dot-separated string indicating the path to the property to replace.
* - Example: `'data.items'` will navigate through `resp.data.items`.
* @param doc - The new data or object to set at the specified path.
* @returns `void`.
*/
private _setObjectToReplace;
/**
* Creates a new object containing only specified fields from the input item.
*
* @param item - The input object to extract fields from.
* @param fields - An array of field names to include in the new object.
* - Example: `['id', 'name']` will create a new object with only the `id` and `name` properties from `item`.
* @returns A new object containing only the specified fields.
*/
private _newDoc;
static ɵfac: i0.ɵɵFactoryDeclaration<HttpService, [{ optional: true; }, null]>;
static ɵprov: i0.ɵɵInjectableDeclaration<HttpService>;
}
declare class NetworkService {
private readonly _isBrowser;
/** Internal mutable signals. */
private _status;
private _latencyMs;
private _isOnline;
/** Public read-only signals. */
readonly status: i0.Signal<NetworkStatus>;
readonly latencyMs: i0.Signal<number | null>;
readonly isOnline: i0.Signal<boolean>;
/** Failure counter to decide "none". */
private _fails;
/**
* Creates the network monitor, binds browser/Capacitor events,
* performs an immediate check, and starts periodic polling.
*/
constructor(config: Config);
/**
* Manually trigger a connectivity check.
* - Measures latency against the first reachable endpoint.
* - Updates `isOnline`, `latencyMs`, and `status` accordingly.
*/
recheckNow(): Promise<void>;
/**
* Classifies current state into 'good' | 'poor' | 'none'.
* - 'none' if offline or too many consecutive failures.
* - 'good' if latency ≤ goodLatencyMs.
* - otherwise 'poor'.
*/
private _updateClassification;
/**
* Binds browser events that can affect connectivity:
* - online/offline (OS connectivity)
* - visibilitychange (recheck on focus)
* - NetworkInformation 'change' (if supported)
*/
private _bindEvents;
/**
* Tries endpoints in order until one responds (CORS or opaque).
* Returns success with measured latency, or a failure result.
*/
private _pingAny;
/**
* Measures a single fetch:
* - Appends a timestamp to bypass caches.
* - Uses `no-store` to avoid intermediaries caching.
* - When `noCors` is true, uses `mode:'no-cors'` and treats a resolved fetch as reachable.
*/
private _measure;
private _config;
private _emitterService;
static ɵfac: i0.ɵɵFactoryDeclaration<NetworkService, [{ optional: true; }]>;
static ɵprov: i0.ɵɵInjectableDeclaration<NetworkService>;
}
declare class StoreService {
private readonly _isBrowser;
private _prefix;
private _config;
constructor(config: Config);
/**
* Sets the prefix for storage keys.
*/
setPrefix(prefix: string): void;
/**
* Stores a raw string value.
*/
set(key: string, value: string, options?: StoreOptions): Promise<boolean>;
/**
* Retrieves a raw string value.
*/
get(key: string, options?: StoreOptions<string>): Promise<string | null>;
/**
* Stores a JSON value safely.
*/
setJson<T>(key: string, value: T, options?: StoreOptions): Promise<boolean>;
/**
* Retrieves a JSON value safely (auto-heals broken data).
*/
getJson<T = unknown>(key: string, options?: StoreOptions<T>): Promise<T | null>;
/**
* Removes a single key.
*/
remove(key: string, options?: StoreOptions): Promise<boolean>;
/**
* Clears all storage.
*/
clear(options?: StoreOptions): Promise<boolean>;
/**
* Applies configured prefixes to key.
*/
private _applyPrefix;
static ɵfac: i0.ɵɵFactoryDeclaration<StoreService, [{ optional: true; }]>;
static ɵprov: i0.ɵɵInjectableDeclaration<StoreService>;
}
/**
* Abstract class representing a CRUD (Create, Read, Update, Delete) service.
*
* This class provides methods for managing documents, interacting with an API,
* and storing/retrieving data from local storage. It is designed to be extended
* for specific document types.
*
* @template Document - The type of the document the service handles.
*/
declare abstract class CrudService<Document extends CrudDocument<Document>> {
private _config;
private readonly _isBrowser;
/**
* Base URL for the API collection associated with this service.
*/
private _url;
/**
* In-memory cache with all documents currently known by the service.
*/
private _docs;
/**
* Number of documents per page for paginated `get()` calls.
*/
private _perPage;
/**
* Registered callbacks that recompute filtered document views.
*/
private _filteredDocumentsCallbacks;
/**
* HTTP client wrapper used for API communication.
*/
protected __httpService: HttpService;
/**
* Key–value storage service used to persist documents locally.
*/
protected __storeService: StoreService;
/**
* Core helper service with utility methods (copy, debounce, toSignal, etc.).
*/
protected __coreService: CoreService;
/**
* Global event bus for cross-service communication.
*/
protected __emitterService: EmitterService;
/**
* Network status service used to queue work while offline.
*/
protected __networkService: NetworkService;
/**
* Emits once when documents are restored from local storage on startup.
*/
loaded: Observable<unknown>;
/**
* Emits once when the initial `get()` (without page param) completes.
*/
getted: Observable<unknown>;
constructor(_config: CrudConfig<Document>);
/**
* Cache of per-document signals indexed by document _id.
* Prevents creating multiple signals for the same document.
*/
private _signal;
/**
* Cache of per (field,value) lists of document signals.
* Key format: `${field}_${JSON.stringify(value)}`.
*/
private _signals;
/**
* Cache of per-field maps: fieldValue -> array of document signals.
*/
private _fieldSignals;
/**
* Returns a WritableSignal for a document by _id, creating it if absent.
* Caches the signal to avoid redundant instances and initializes it
* with the current snapshot of the document.
* Work very carefully with this and localId, better avoid such flows.
*
* @param _id - Document identifier or a document instance.
*/
getSignal(_id: string | Document): WritableSignal<Document>;
/**
* Returns a signal with an array of document signals that match
* a given field/value pair.
*
* Example:
* const activitiesSig = service.getSignals('userId', currentUserId);
*/
getSignals(field: string, value: unknown): WritableSignal<WritableSignal<Document>[]>;
/**
* Builds the array of document signals for a given (field,value) key.
* Only documents with a real _id are included.
*/
private _getSignals;
/**
* Returns a signal with a map: fieldValue -> array of document signals.
*
* Example:
* const byStatusSig = service.getFieldSignals('status');
* byStatusSig() might be { active: [sig1, sig2], draft: [sig3] }.
*/
getFieldSignals(field: string): WritableSignal<Record<string, WritableSignal<Document>[]>>;
/**
* Builds the map for a given field.
* Only documents with a real _id are included.
*/
private _getFieldSignals;
/**
* Clears cached document signals except those explicitly preserved.
* Useful when changing routes or contexts to reduce memory.
*
* @param exceptIds - List of ids whose signals should be kept.
*/
removeSignals(exceptIds?: string[]): void;
/**
* Restores documents from local storage (if present) and syncs
* all existing signals with the restored data.
*/
restoreDocs(): Promise<void>;
/**
* Saves the current set of documents to local storage.
*/
setDocs(): void;
/**
* Retrieves the current list of documents.
*
* @returns The list of documents.
*/
getDocs(filter?: (doc: Document) => boolean): Document[];
/**
* Retrieves the first document that matches the given predicate.
*
* @param find - Predicate used to locate a specific document.
*/
getDoc(find: (doc: Document) => boolean): Document | undefined;
/**
* Clears the current list of documents, persists the empty state
* and recomputes all derived signals.
*
* Empties the internal documents array and saves the updated state to local storage.
*/
clearDocs(): void;
/**
* Adds multiple documents to the service and saves them to local storage.
*
* @param docs - An array of documents to add.
*/
addDocs(docs: Document[]): void;
/**
* Adds a single document to the service. If it already exists, it will be updated.
*
* @param doc - The document to add.
*/
addDoc(doc: Document): void;
/**
* Creates a new document with a temporary ID and status flags.
*
* @param doc - Optional base document to use for the new document.
* @returns A new document instance with default properties.
*/
new(doc?: Document): Document;
/**
* Retrieves a document by its unique ID or creates a new one if it doesn't exist.
*
* @param _id - The document ID to search for.
* @returns The found document or a new document if not found.
*/
doc(_id: string): Document;
/**
* Sets the number of documents to display per page.
*
* @param _perPage - Number of documents per page.
*/
setPerPage(_perPage: number): void;
/**
* Middleware hooks (override in child services).
* Can be sync or async. Must return the document to be sent.
*/
protected beforeCreate(doc: Document, options: CrudOptions<Document>): Document | Promise<Document>;
protected afterCreate(resp: unknown, doc: Document, options: CrudOptions<Document>): void | Promise<void>;
protected beforeUpdate(doc: Document, options: CrudOptions<Document>): Document | Promise<Document>;
protected afterUpdate(resp: unknown, doc: Document, options: CrudOptions<Document>): void | Promise<void>;
protected beforeUnique(doc: Document, options: CrudOptions<Document>): Document | Promise<Document>;
protected afterUnique(resp: unknown, doc: Document, options: CrudOptions<Document>): void | Promise<void>;
protected beforeDelete(doc: Document, options: CrudOptions<Document>): Document | Promise<Document>;
protected afterDelete(resp: unknown, doc: Document, options: CrudOptions<Document>): void | Promise<void>;
protected beforeFetch(query: object, options: CrudOptions<Document>): object | Promise<object>;
protected afterFetch(resp: unknown, query: object, options: CrudOptions<Document>): void | Promise<void>;
/**
* Small helper to normalize sync/async hooks.
*/
private _mw;
/**
* Fetches a list of documents from the API with optional pagination.
*
* @param config - Optional pagination configuration.
* @param options - Optional callback and error handling configuration.
* @returns An observable that resolves with the list of documents.
*/
get(config?: GetConfig, options?: CrudOptions<Document>): Observable<Document[]>;
/**
* Sends a request to the API to create a new document.
*
* @param doc - The document to create.
* @param options - Optional callback and error handling configuration.
* @returns An observable that resolves with the created document, or emits an error if already created.
*/
create(doc?: Document, options?: CrudOptions<Document>): Observable<Document>;
/**
* Fetches a document from the API based on a query.
*
* @param query - The query object used to filter documents.
* @param options - Optional callback and error handling configuration.
* @returns An observable that resolves with the fetched document.
*/
fetch(query?: object, options?: CrudOptions<Document>): Observable<Document>;
/**
* Updates a document after a specified delay and returns an observable.
*
* @param doc - The document to update.
* @param options - Optional callback and error handling configuration.
* @returns An observable that emits the updated document.
*/
updateAfterWhile(doc: Document, options?: CrudOptions<Document>): Observable<Document>;
/**
* Updates a document in the API.
*
* @param doc - The document to update.
* @param options - Optional callback and error handling configuration.
* @returns An observable that resolves with the updated document.
*/
update(doc: Document, options?: CrudOptions<Document>): Observable<Document>;
/**
* Unique update a document field in the API.
*
* @param doc - The document to update.
* @param options - Optional callback and error handling configuration.
* @returns An observable that resolves with the updated document.
*/
unique(doc: Document, options?: CrudOptions<Document>): Observable<Document>;
/**
* Deletes a document from the API.
*
* @param doc - The document to delete.
* @param options - Optional callback and error handling configuration.
* @returns An observable that resolves with the deleted document.
*/
delete(doc: Document, options?: CrudOptions<Document>): Observable<Document>;
/**
* Registers a filtered view of documents and returns the recompute callback.
*
* The callback is called automatically whenever `_filterDocuments()` runs.
*/
filteredDocuments(storeObjectOrArray: Record<string, Document[]> | Document[], config?: {
field?: string | ((doc: Document) => string);
valid?: (doc: Document) => boolean;
sort?: (a: Document, b: Document) => number;
filtered?: (storeObjectOrArray: Record<string, Document[]> | Document[]) => void;
}): () => void;
/**
* Track pending fetch-by-id requests to avoid duplicate calls.
*/
private _fetchingId;
/**
* Queue of operations that must be retried when network comes back online.
*/
private _onOnline;
/**
* Local counter used to build unique local identifiers together with Date.now().
*/
private _randomCount;
/**
* Generates a unique ID for a document when using local-only identifiers.
*
* @returns The unique ID as a number.
*/
private _localId;
/**
* Returns the configured identity field for the given document as string.
*
* @param doc - The document for which to generate the ID.
* @returns The unique ID as a string.
*/
private _id;
/**
* Executes all registered filter document callbacks and emits a
* `<name>_filtered` event.
*/
private _filterDocuments;
/**
* Marks a document as modified for a given operation id and
* keeps the document in the store until the operation is confirmed.
*/
private _updateModified;
/**
* Removes a modification mark from the document once the
* server operation is confirmed.
*/
private _removeModified;
/**
* Syncs a single document's signal (if exists) and refreshes all
* derived collections (field/value lists and field maps).
*/
private _syncSignalForDoc;
/**
* Rebuilds all derived signal collections:
* - all per (field,value) lists of document signals
* - all per-field maps value -> [signals]
*
* This keeps `getSignals()` and `getFieldSignals()` in sync after
* any mutation that touches `_docs`.
*/
private _updateSignals;
}
type ThemeMode = 'light' | 'dark' | string;
type ThemeDensity = 'comfortable' | 'compact' | string;
type ThemeRadius = 'rounded' | 'square' | string;
declare class ThemeService {
private readonly _doc;
private readonly _isBrowser;
mode: i0.WritableSignal<string | undefined>;
modes: i0.WritableSignal<string[]>;
setMode(mode: ThemeMode): void;
density: i0.WritableSignal<string | undefined>;
densities: i0.WritableSignal<string[]>;
setDensity(density: ThemeDensity): void;
radius: i0.WritableSignal<string | undefined>;
radiuses: i0.WritableSignal<string[]>;
setRadius(radius: ThemeRadius): void;
themeIndex: i0.WritableSignal<number>;
nextTheme(): void;
init(): void;
static ɵfac: i0.ɵɵFactoryDeclaration<ThemeService, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<ThemeService>;
}
/**
* Centralized page meta management for SPA navigation.
*
* Goals:
* - Static SEO pages: route-driven meta via `data.meta`
* - Dynamic/id pages: manual meta via `applyMeta(...)`
* - No stale meta: tags set for one page must not "leak" to another page
* - Simple inputs: only title/description/image/index/robots (everything else auto-generated)
* - Links handled separately: `setLink({ canonical: '...' })` updates, never duplicates
*
* Generated tags:
* - Title:
* - <title>
* - <meta itemprop="name" ...>
* - <meta property="og:title" ...>
* - <meta name="twitter:title" ...>
* - Description:
* - <meta name="description" ...>
* - <meta itemprop="description" ...>
* - <meta property="og:description" ...>
* - <meta name="twitter:description" ...>
* - Image:
* - <meta itemprop="image" ...>
* - <meta property="og:image" ...>
* - <meta name="twitter:image:src" ...>
* - Robots:
* - <meta name="robots" ...> (derived from `robots` or `index`)
*/
declare class MetaService {
private _config;
private _router;
private _activatedRoute;
private _meta;
private _titleService;
private readonly _isBrowser;
/**
* Effective configuration (from CONFIG_TOKEN + DEFAULT_CONFIG fallback).
*/
private _metaConfig;
/**
* Meta tags that are "owned" by this service.
* We remove these on every `applyMeta()` so stale tags never survive SPA navigation.
*
* Stored as selectors compatible with Angular Meta.removeTag(), e.g.:
* - name="description"
* - property="og:title"
* - itemprop="image"
*/
private _managedTagSelectors;
/**
* Link rels that are managed by this service.
* Used to update links without duplicates and optionally remove them via resetLinks().
*/
private _managedLinkRels;
constructor(_config: Config, _router: Router, _activatedRoute: ActivatedRoute, _meta: Meta, _titleService: Title);
/**
* Merge and set defaults.
*
* Defaults are used when a page does not provide a given field.
* This affects:
* - applyMeta() fallbacks
* - reset()
*/
setDefaults(defaults: MetaDefaults): void;
/**
* Apply metadata for the current page.
*
* Use cases:
* - Static SEO pages: route data (`data.meta`) when applyFromRoutes = true
* - Dynamic / id pages: call manually after loading entity data
*
* Rules:
* 1) remove tags previously managed by this service
* 2) start from defaults
* 3) override with page values
* 4) generate OG/Twitter/itemprop variants
*/
applyMeta(page?: MetaPage): void;
/**
* Reset page meta back to defaults.
*
* Removes all managed tags and re-applies defaults-only meta.
*/
reset(): void;
/**
* Sets link tags (canonical, alternate, etc.) without duplicates.
*
* For each rel:
* - if link[rel=rel] exists -> update href
* - else -> create it
* - if duplicates exist -> remove extras
*/
setLink(links: Record<string, string>): void;
/**
* Removes link tags that were managed by this service via setLink().
*
* Note:
* - Not called by reset() because canonical often should persist for the whole app shell.
* - Call explicitly if you want to remove canonical/alternate links.
*/
resetLinks(): void;
/**