@zssz-soft/core-api 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/fesm2022/zssz-soft-core-api.mjs +399 -0
- package/fesm2022/zssz-soft-core-api.mjs.map +1 -0
- package/package.json +49 -0
- package/types/zssz-soft-core-api.d.ts +1633 -0
|
@@ -0,0 +1,1633 @@
|
|
|
1
|
+
import { Identifiable, Meta, EntityTypeEnum, User, QueryOptions, CursorPaginatedResult, PaginatedResult, SearchParam, Message } from '@zssz-soft/common-api';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import * as _angular_core from '@angular/core';
|
|
4
|
+
import { Signal, InjectionToken, Provider, PipeTransform } from '@angular/core';
|
|
5
|
+
import { FormGroup } from '@angular/forms';
|
|
6
|
+
import { KeyValue } from '@angular/common';
|
|
7
|
+
import { SelectEntityId, EntityId } from '@ngrx/signals/entities';
|
|
8
|
+
import { HttpClient } from '@angular/common/http';
|
|
9
|
+
import { Translation } from '@jsverse/transloco';
|
|
10
|
+
import { DateFormatOptions } from '@jsverse/transloco-locale';
|
|
11
|
+
|
|
12
|
+
interface EntityHelper {
|
|
13
|
+
meta: Meta;
|
|
14
|
+
}
|
|
15
|
+
type Entity = Identifiable & EntityHelper;
|
|
16
|
+
type EntityAdd = Omit<Entity, 'uid'>;
|
|
17
|
+
type EntityUpdate = Partial<Entity> & Identifiable & EntityHelper;
|
|
18
|
+
type EntityModel = Entity;
|
|
19
|
+
type EntityModelAdd = Omit<EntityModel, 'uid'>;
|
|
20
|
+
type EntityModelUpdate = Partial<EntityModel> & Identifiable & EntityHelper;
|
|
21
|
+
type EntityType = EntityTypeEnum.Entity;
|
|
22
|
+
type CustomEntityState = {
|
|
23
|
+
isLoading: boolean;
|
|
24
|
+
isNewEntityButtonEnabled: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
interface EntityCollectionStoreView<E extends Entity> {
|
|
28
|
+
editEntity(entity: E): void;
|
|
29
|
+
deleteEntity(entity: E): void;
|
|
30
|
+
setSearchTerm(searchTerm: string): void;
|
|
31
|
+
setSorting(field: string, order: 'asc' | 'desc'): void;
|
|
32
|
+
setViewMode(viewMode: 'table' | 'dataview' | 'cards'): void;
|
|
33
|
+
toggleSortOrder(): void;
|
|
34
|
+
entities: Signal<E[]>;
|
|
35
|
+
isLoading: Signal<boolean>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare abstract class EntityFormLogic<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate> {
|
|
39
|
+
abstract cancel(): void;
|
|
40
|
+
abstract createEntity(formValue: any): void;
|
|
41
|
+
abstract createFormGroup(entity?: E): FormGroup;
|
|
42
|
+
abstract getEntityById(entityId: string): E | undefined;
|
|
43
|
+
abstract updateEntity(entityId: string, formValue: any): void;
|
|
44
|
+
abstract validateAndProcessForm(form: FormGroup | null, entityId: string | null): {
|
|
45
|
+
isValid: boolean;
|
|
46
|
+
formValue?: any;
|
|
47
|
+
entityId?: string | null;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface EntityFormStoreView<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate> {
|
|
52
|
+
cancel(): void;
|
|
53
|
+
createEntity(formValue: any): void;
|
|
54
|
+
createFormGroup(entity: E | undefined): FormGroup;
|
|
55
|
+
updateEntity(entityId: string, formValue: any): void;
|
|
56
|
+
formGroup(): FormGroup | undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Interface defining the contract for entity table stores.
|
|
61
|
+
* Provides standard methods for table operations like editing, deleting, and navigation.
|
|
62
|
+
*/
|
|
63
|
+
interface EntityTableStoreView<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate> {
|
|
64
|
+
editEntity(entity: E): void;
|
|
65
|
+
deleteEntity(entity: E): void;
|
|
66
|
+
navigateToCreate(): void;
|
|
67
|
+
navigateToEdit(entityId: string): void;
|
|
68
|
+
setViewMode(viewMode: 'table' | 'dataview' | 'cards'): void;
|
|
69
|
+
setSearchTerm(searchTerm: string): void;
|
|
70
|
+
setSorting(field: string, order: 'asc' | 'desc'): void;
|
|
71
|
+
clearFilters(): void;
|
|
72
|
+
setCurrentPage(page: number): void;
|
|
73
|
+
setPageSize(size: number): void;
|
|
74
|
+
refresh(): void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Interface defining the contract for resource-based entity table stores.
|
|
79
|
+
* Uses cursor-based pagination for Firestore cost optimization.
|
|
80
|
+
*/
|
|
81
|
+
interface EntityTableResourceStoreView<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate> {
|
|
82
|
+
editEntity(entity: E): void;
|
|
83
|
+
deleteEntity(entity: E): void;
|
|
84
|
+
navigateToCreate(): void;
|
|
85
|
+
navigateToEdit(entityId: string): void;
|
|
86
|
+
setViewMode(viewMode: 'table' | 'dataview' | 'cards'): void;
|
|
87
|
+
setSearchTerm(searchTerm: string): void;
|
|
88
|
+
setSorting(field: string, order: 'asc' | 'desc'): void;
|
|
89
|
+
clearFilters(): void;
|
|
90
|
+
loadNextPage(): void;
|
|
91
|
+
resetPagination(): void;
|
|
92
|
+
setPageSize(size: number): void;
|
|
93
|
+
refresh(): void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declare abstract class EntityAdapter<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate, EM extends EntityModel, EMA extends EntityModelAdd, EMU extends EntityModelUpdate> {
|
|
97
|
+
user: Signal<User | undefined>;
|
|
98
|
+
abstract _sort(a: E, b: E): number;
|
|
99
|
+
abstract convertEntityAddToModelAdd(entityAdd: EA): EMA;
|
|
100
|
+
abstract convertEntityToModel(entity: E): EM;
|
|
101
|
+
abstract convertEntityUpdateToModelUpdate(entity: EU): EMU;
|
|
102
|
+
abstract convertModelToEntity(model: EM): E;
|
|
103
|
+
abstract convertModelUpdateToEntityUpdate(model: EMU): EU;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Abstract base class for entity effects
|
|
108
|
+
*
|
|
109
|
+
* Design Pattern: Template Method Pattern
|
|
110
|
+
* - Definiálja az entity műveletek absztrakt szerződését
|
|
111
|
+
* - A konkrét implementációk a domain-specifikus logikát adják
|
|
112
|
+
*
|
|
113
|
+
* Effects felelősségei:
|
|
114
|
+
* - Adapter hívások koordinálása (Entity <-> Model konverzió)
|
|
115
|
+
* - Error handling és logging
|
|
116
|
+
* - Repository művelet delegálás
|
|
117
|
+
*/
|
|
118
|
+
declare abstract class EntityEffect<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate> {
|
|
119
|
+
abstract createEntity$(entityAdd: EA): Observable<E>;
|
|
120
|
+
abstract deleteEntity$(entity: E): Observable<E>;
|
|
121
|
+
abstract listEntities$(pathParams: string[], queryParams: KeyValue<string, string>[]): Observable<E[]>;
|
|
122
|
+
abstract loadEntity$(entityId: string): Observable<E>;
|
|
123
|
+
abstract updateEntity$(entityUpdate: EU): Observable<EU>;
|
|
124
|
+
/**
|
|
125
|
+
* Query entities with cursor-based pagination
|
|
126
|
+
* Optional method - can be overridden by domain effects for optimized queries
|
|
127
|
+
*
|
|
128
|
+
* @param options Query options including filters, sorting, and pagination
|
|
129
|
+
* @returns Observable of cursor-paginated result
|
|
130
|
+
*/
|
|
131
|
+
queryCursorPaginated$(_options: QueryOptions): Observable<CursorPaginatedResult<E>>;
|
|
132
|
+
/**
|
|
133
|
+
* Query entities by parent ID (for subcollections)
|
|
134
|
+
* Optional method - can be overridden by effects that handle subcollections
|
|
135
|
+
*
|
|
136
|
+
* @param parentId The ID of the parent entity
|
|
137
|
+
* @param options Optional query options
|
|
138
|
+
* @returns Observable of entities belonging to parent
|
|
139
|
+
*/
|
|
140
|
+
queryByParentId$(_parentId: string, _options?: QueryOptions): Observable<E[]>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Batch operation interface
|
|
145
|
+
*/
|
|
146
|
+
interface BatchOperation<T> {
|
|
147
|
+
type: 'create' | 'update' | 'delete';
|
|
148
|
+
uid?: string;
|
|
149
|
+
data?: Partial<T>;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Context for resolving subcollection paths in Firestore
|
|
153
|
+
* Enables repositories to work with nested collections (e.g., apartments/{id}/rules)
|
|
154
|
+
*/
|
|
155
|
+
interface SubcollectionContext {
|
|
156
|
+
/**
|
|
157
|
+
* Name of parent collection (e.g., 'apartments')
|
|
158
|
+
*/
|
|
159
|
+
parentCollection: string;
|
|
160
|
+
/**
|
|
161
|
+
* Field name on the entity that contains parent ID (e.g., 'entityId', 'apartmentId')
|
|
162
|
+
*/
|
|
163
|
+
parentIdField: string;
|
|
164
|
+
/**
|
|
165
|
+
* Name of subcollection (e.g., 'rules')
|
|
166
|
+
*/
|
|
167
|
+
subcollection: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Builder function type for dynamic collection paths
|
|
171
|
+
* Takes optional entity data and returns the resolved collection path
|
|
172
|
+
*/
|
|
173
|
+
type CollectionPathBuilder = (entityData?: Partial<EntityModel>) => string;
|
|
174
|
+
/**
|
|
175
|
+
* Abstract base repository interface for database operations
|
|
176
|
+
* This interface defines the contract that all data repositories must implement
|
|
177
|
+
*/
|
|
178
|
+
declare abstract class Repository<EM extends EntityModel, EMA extends EntityModelAdd, EMU extends EntityModelUpdate> {
|
|
179
|
+
abstract create$(modelAdd: EMA): Observable<EM>;
|
|
180
|
+
abstract list$(pathParams: string[], queryParams: KeyValue<string, string>[]): Observable<EM[]>;
|
|
181
|
+
abstract listByIds$(ids: string[]): Observable<EM[]>;
|
|
182
|
+
abstract load$(uid: string): Observable<EM | undefined>;
|
|
183
|
+
abstract update$(modelUpdate: EMU): Observable<EMU>;
|
|
184
|
+
abstract delete$(model: EM): Observable<EM>;
|
|
185
|
+
abstract query(options: QueryOptions): Observable<EM[]>;
|
|
186
|
+
abstract queryPaginated(options: QueryOptions, pageSize: number, lastDocument?: EM): Observable<PaginatedResult<EM>>;
|
|
187
|
+
abstract count(options?: QueryOptions): Observable<number>;
|
|
188
|
+
abstract exists(uid: string): Observable<boolean>;
|
|
189
|
+
abstract batch(operations: BatchOperation<EM>[]): Observable<void>;
|
|
190
|
+
abstract search$(params: SearchParam[]): Observable<EM[]>;
|
|
191
|
+
/**
|
|
192
|
+
* Query entities by parent ID (for subcollections)
|
|
193
|
+
* Optional - only implemented for repositories with subcollection context
|
|
194
|
+
* @param parentId The ID of the parent entity
|
|
195
|
+
* @param options Optional query options for filtering/sorting
|
|
196
|
+
*/
|
|
197
|
+
queryByParentId?(parentId: string, options?: QueryOptions): Observable<EM[]>;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
declare abstract class RepositoryEngine<E extends EntityModel, EA extends EntityModelAdd, EU extends EntityModelUpdate> extends Repository<E, EA, EU> {
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Type for a factory function that creates a repository engine
|
|
205
|
+
*/
|
|
206
|
+
type RepositoryEngineCreator = <R extends EntityModel, S extends EntityModelAdd, T extends EntityModelUpdate>(featureKey: string, subcollectionContext?: SubcollectionContext) => RepositoryEngine<R, S, T>;
|
|
207
|
+
/**
|
|
208
|
+
* Injection token for the Firestore engine creator function
|
|
209
|
+
* This allows the actual Firebase implementation to be provided at the app level
|
|
210
|
+
* while keeping the factory testable
|
|
211
|
+
*/
|
|
212
|
+
declare const FIRESTORE_ENGINE_CREATOR: InjectionToken<RepositoryEngineCreator>;
|
|
213
|
+
|
|
214
|
+
declare abstract class EntityRepository<EM extends EntityModel, EMA extends EntityModelAdd, EU extends EntityModelUpdate> extends Repository<EM, EMA, EU> {
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
interface EntityActions<E extends Entity> {
|
|
218
|
+
setLoading(isLoading: boolean): void;
|
|
219
|
+
setNewEntityButtonEnabled(enabled: boolean): void;
|
|
220
|
+
setSearchResult(searchResult: E[]): void;
|
|
221
|
+
setSelectedEntityId(selectedEntityId: string | undefined): void;
|
|
222
|
+
}
|
|
223
|
+
interface EntityConfig<E extends Entity> {
|
|
224
|
+
collection: string;
|
|
225
|
+
entity: E;
|
|
226
|
+
selectId: SelectEntityId<NoInfer<E>>;
|
|
227
|
+
}
|
|
228
|
+
interface EntitySignals<A extends string, E extends Entity> {
|
|
229
|
+
all: Signal<E[]>;
|
|
230
|
+
count: Signal<number>;
|
|
231
|
+
entities: Signal<Record<A, E>>;
|
|
232
|
+
error: Signal<string | null>;
|
|
233
|
+
ids: Signal<A[]>;
|
|
234
|
+
isLoading: Signal<boolean>;
|
|
235
|
+
selected: Signal<E | undefined>;
|
|
236
|
+
selectedId: Signal<A | null>;
|
|
237
|
+
selectEntityById(): Signal<E | undefined>;
|
|
238
|
+
}
|
|
239
|
+
interface EntityStore<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate, V extends string> extends EntitySignals<V, E>, RxEntityActions<E, EA, EU>, EntityActions<E> {
|
|
240
|
+
}
|
|
241
|
+
interface RxEntityActions<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate> {
|
|
242
|
+
createEntity$(entityAdd: EA): void;
|
|
243
|
+
deleteEntity$(entity: E): void;
|
|
244
|
+
listEntities$(): void;
|
|
245
|
+
updateEntity$(entityUpdate: EU): void;
|
|
246
|
+
}
|
|
247
|
+
interface EntityStoreView<E extends Entity, EA extends EntityAdd, EU extends EntityUpdate> {
|
|
248
|
+
entityMap: Signal<Record<string, E>>;
|
|
249
|
+
ids: Signal<EntityId[]>;
|
|
250
|
+
entities: Signal<E[]>;
|
|
251
|
+
selectedEntityId: Signal<string | undefined>;
|
|
252
|
+
isLoading: Signal<boolean>;
|
|
253
|
+
isNewEntityButtonEnabled: Signal<boolean>;
|
|
254
|
+
searchResult: Signal<E[]>;
|
|
255
|
+
error: Signal<string | null>;
|
|
256
|
+
getEntityBySelectedId: Signal<E | undefined>;
|
|
257
|
+
resourceEntities?: Signal<E[]>;
|
|
258
|
+
hasNextPage?: Signal<boolean>;
|
|
259
|
+
hasPreviousPage?: Signal<boolean>;
|
|
260
|
+
isLoaded?: Signal<boolean>;
|
|
261
|
+
getEntityById(entityId: string): E | undefined;
|
|
262
|
+
setSelectedEntityId(id?: string): void;
|
|
263
|
+
setNewEntityButtonEnabled(enabled: boolean): void;
|
|
264
|
+
setSearchResult(results: E[]): void;
|
|
265
|
+
setLoading(loading: boolean): void;
|
|
266
|
+
setQueryOptions?(options: QueryOptions): void;
|
|
267
|
+
updateQueryOptions?(options: Partial<QueryOptions>): void;
|
|
268
|
+
loadNextPage?(): void;
|
|
269
|
+
resetPagination?(): void;
|
|
270
|
+
reload?(): void;
|
|
271
|
+
parentId?: Signal<string | null>;
|
|
272
|
+
subcollectionOptions?: Signal<QueryOptions | null>;
|
|
273
|
+
loadEntitiesByParentId?(parentId: string, options?: QueryOptions): Promise<E[]>;
|
|
274
|
+
listEntities(params: {
|
|
275
|
+
pathParams: string[];
|
|
276
|
+
queryParams: KeyValue<string, string>[];
|
|
277
|
+
}): Promise<E[]>;
|
|
278
|
+
createEntity(entity: EA): Promise<E>;
|
|
279
|
+
updateEntity(entity: EU): Promise<EU>;
|
|
280
|
+
deleteEntity(entity: E): Promise<E>;
|
|
281
|
+
loadEntity(id: string): Promise<E>;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
declare const AUDIT_FEATURE_KEY = "audit_logs";
|
|
285
|
+
/**
|
|
286
|
+
* Audit log entry for tracking user actions
|
|
287
|
+
*/
|
|
288
|
+
interface AuditLog {
|
|
289
|
+
/** Unique audit log ID */
|
|
290
|
+
id?: string;
|
|
291
|
+
/** User who performed the action */
|
|
292
|
+
user: User | string;
|
|
293
|
+
/** Action performed */
|
|
294
|
+
action: AuditAction;
|
|
295
|
+
/** Resource affected by the action */
|
|
296
|
+
resource: AuditResource;
|
|
297
|
+
/** Timestamp when action occurred */
|
|
298
|
+
timestamp: Date;
|
|
299
|
+
/** Session information */
|
|
300
|
+
sessionId?: string;
|
|
301
|
+
/** Request metadata */
|
|
302
|
+
metadata: AuditMetadata;
|
|
303
|
+
/** Action result */
|
|
304
|
+
result: AuditResult;
|
|
305
|
+
/** Additional context data */
|
|
306
|
+
context?: Record<string, any>;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Types of actions that can be audited
|
|
310
|
+
*/
|
|
311
|
+
type AuditAction = 'auth.login' | 'auth.logout' | 'auth.register' | 'auth.password_reset' | 'auth.email_verification' | 'user.create' | 'user.update' | 'user.delete' | 'user.role_change' | 'user.status_change' | 'data.create' | 'data.read' | 'data.update' | 'data.delete' | 'data.export' | 'data.import' | 'system.configuration_change' | 'system.backup' | 'system.restore' | 'ui.page_view' | 'ui.button_click' | 'ui.form_submit' | 'ui.theme_change' | 'ui.search' | 'ui.filter' | 'ui.download' | 'ui.upload' | 'security.unauthorized_access' | 'security.permission_denied' | 'security.suspicious_activity' | string;
|
|
312
|
+
/**
|
|
313
|
+
* Resource types that can be audited
|
|
314
|
+
*/
|
|
315
|
+
interface AuditResource {
|
|
316
|
+
/** Type of resource */
|
|
317
|
+
type: string;
|
|
318
|
+
/** Resource identifier */
|
|
319
|
+
id?: string;
|
|
320
|
+
/** Resource name or description */
|
|
321
|
+
name?: string;
|
|
322
|
+
/** Parent resource if applicable */
|
|
323
|
+
parent?: AuditResource;
|
|
324
|
+
/** Additional resource metadata */
|
|
325
|
+
metadata?: Record<string, any>;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Metadata associated with an audit action
|
|
329
|
+
*/
|
|
330
|
+
interface AuditMetadata {
|
|
331
|
+
/** IP address of the request */
|
|
332
|
+
ipAddress?: string;
|
|
333
|
+
/** User agent string */
|
|
334
|
+
userAgent?: string;
|
|
335
|
+
/** Geographic location */
|
|
336
|
+
location?: {
|
|
337
|
+
country?: string;
|
|
338
|
+
region?: string;
|
|
339
|
+
city?: string;
|
|
340
|
+
coordinates?: {
|
|
341
|
+
latitude: number;
|
|
342
|
+
longitude: number;
|
|
343
|
+
};
|
|
344
|
+
};
|
|
345
|
+
/** Request information */
|
|
346
|
+
request?: {
|
|
347
|
+
method?: string;
|
|
348
|
+
url?: string;
|
|
349
|
+
headers?: Record<string, string>;
|
|
350
|
+
body?: any;
|
|
351
|
+
};
|
|
352
|
+
/** Response information */
|
|
353
|
+
response?: {
|
|
354
|
+
statusCode?: number;
|
|
355
|
+
headers?: Record<string, string>;
|
|
356
|
+
body?: any;
|
|
357
|
+
};
|
|
358
|
+
/** Performance metrics */
|
|
359
|
+
performance?: {
|
|
360
|
+
duration?: number;
|
|
361
|
+
memoryUsage?: number;
|
|
362
|
+
cpuUsage?: number;
|
|
363
|
+
};
|
|
364
|
+
/** Additional custom metadata */
|
|
365
|
+
[key: string]: any;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Result of an audited action
|
|
369
|
+
*/
|
|
370
|
+
interface AuditResult {
|
|
371
|
+
/** Whether the action was successful */
|
|
372
|
+
success: boolean;
|
|
373
|
+
/** Status code or error code */
|
|
374
|
+
code?: string | number;
|
|
375
|
+
/** Human-readable message */
|
|
376
|
+
message?: string;
|
|
377
|
+
/** Error details if action failed */
|
|
378
|
+
error?: {
|
|
379
|
+
type: string;
|
|
380
|
+
message: string;
|
|
381
|
+
stack?: string;
|
|
382
|
+
};
|
|
383
|
+
/** Changes made (for update actions) */
|
|
384
|
+
changes?: {
|
|
385
|
+
before?: any;
|
|
386
|
+
after?: any;
|
|
387
|
+
fields?: string[];
|
|
388
|
+
};
|
|
389
|
+
/** Additional result data */
|
|
390
|
+
data?: any;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Audit log query filters
|
|
394
|
+
*/
|
|
395
|
+
interface AuditLogQuery {
|
|
396
|
+
/** Filter by user */
|
|
397
|
+
userId?: string;
|
|
398
|
+
/** Filter by action */
|
|
399
|
+
action?: AuditAction | AuditAction[];
|
|
400
|
+
/** Filter by resource type */
|
|
401
|
+
resourceType?: string;
|
|
402
|
+
/** Filter by date range */
|
|
403
|
+
dateRange?: {
|
|
404
|
+
start: Date;
|
|
405
|
+
end: Date;
|
|
406
|
+
};
|
|
407
|
+
/** Filter by success/failure */
|
|
408
|
+
success?: boolean;
|
|
409
|
+
/** Filter by session ID */
|
|
410
|
+
sessionId?: string;
|
|
411
|
+
/** Filter by IP address */
|
|
412
|
+
ipAddress?: string;
|
|
413
|
+
/** Pagination */
|
|
414
|
+
limit?: number;
|
|
415
|
+
offset?: number;
|
|
416
|
+
/** Sorting */
|
|
417
|
+
sortBy?: 'timestamp' | 'action' | 'user';
|
|
418
|
+
sortOrder?: 'asc' | 'desc';
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Audit log summary statistics
|
|
422
|
+
*/
|
|
423
|
+
interface AuditLogStats {
|
|
424
|
+
/** Total number of logs */
|
|
425
|
+
totalLogs: number;
|
|
426
|
+
/** Actions by type */
|
|
427
|
+
actionCounts: Record<string, number>;
|
|
428
|
+
/** Success rate */
|
|
429
|
+
successRate: number;
|
|
430
|
+
/** Most active users */
|
|
431
|
+
topUsers: Array<{
|
|
432
|
+
userId: string;
|
|
433
|
+
actionCount: number;
|
|
434
|
+
}>;
|
|
435
|
+
/** Most common actions */
|
|
436
|
+
topActions: Array<{
|
|
437
|
+
action: string;
|
|
438
|
+
count: number;
|
|
439
|
+
}>;
|
|
440
|
+
/** Date range covered */
|
|
441
|
+
dateRange: {
|
|
442
|
+
start: Date;
|
|
443
|
+
end: Date;
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
interface Audit {
|
|
447
|
+
/** User who performed the action */
|
|
448
|
+
user: User | string;
|
|
449
|
+
/** Action performed */
|
|
450
|
+
action: AuditAction;
|
|
451
|
+
/** Resource affected by the action */
|
|
452
|
+
resource: AuditResource;
|
|
453
|
+
/** Timestamp when action occurred */
|
|
454
|
+
timestamp: Date;
|
|
455
|
+
/** Session information */
|
|
456
|
+
sessionId?: string;
|
|
457
|
+
/** Request metadata */
|
|
458
|
+
metadata: AuditMetadata;
|
|
459
|
+
/** Action result */
|
|
460
|
+
result: AuditResult;
|
|
461
|
+
/** Additional context data */
|
|
462
|
+
context?: Record<string, any>;
|
|
463
|
+
}
|
|
464
|
+
type AuditEntity = Audit & Entity;
|
|
465
|
+
type AuditEntityAdd = Omit<AuditEntity, 'uid'>;
|
|
466
|
+
type AuditEntityUpdate = Partial<AuditEntity> & Entity;
|
|
467
|
+
type AuditModel = Audit & EntityModel;
|
|
468
|
+
type AuditModelAdd = Omit<AuditModel, 'uid'>;
|
|
469
|
+
type AuditModelUpdate = Partial<AuditModel> & EntityModel;
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Abstract interface for audit logging operations
|
|
473
|
+
* This defines the contract for audit logging without implementation details
|
|
474
|
+
*/
|
|
475
|
+
declare abstract class AuditService {
|
|
476
|
+
/**
|
|
477
|
+
* Log a user action with result
|
|
478
|
+
* @param user User performing the action
|
|
479
|
+
* @param action Action being performed
|
|
480
|
+
* @param resource Resource being acted upon
|
|
481
|
+
* @param result Action result (success/failure)
|
|
482
|
+
* @param context Additional context data
|
|
483
|
+
* @returns Observable with the audit log ID
|
|
484
|
+
*/
|
|
485
|
+
abstract logAction(user: User, action: AuditAction, resource: AuditResource, result: 'success' | 'failure', context?: Record<string, any>): Observable<string>;
|
|
486
|
+
/**
|
|
487
|
+
* Log a successful action
|
|
488
|
+
* @param user User performing the action
|
|
489
|
+
* @param action Action being performed
|
|
490
|
+
* @param resource Resource being acted upon
|
|
491
|
+
* @param data Additional data about the action
|
|
492
|
+
* @param context Additional context data
|
|
493
|
+
* @returns Observable with the audit log ID
|
|
494
|
+
*/
|
|
495
|
+
abstract logSuccess(user: User, action: AuditAction, resource: AuditResource, data?: any, context?: Record<string, any>): Observable<string>;
|
|
496
|
+
/**
|
|
497
|
+
* Log a failed action
|
|
498
|
+
* @param user User performing the action
|
|
499
|
+
* @param action Action being performed
|
|
500
|
+
* @param resource Resource being acted upon
|
|
501
|
+
* @param error Error that occurred
|
|
502
|
+
* @param context Additional context data
|
|
503
|
+
* @returns Observable with the audit log ID
|
|
504
|
+
*/
|
|
505
|
+
abstract logFailure(user: User, action: AuditAction, resource: AuditResource, error: Error, context?: Record<string, any>): Observable<string>;
|
|
506
|
+
/**
|
|
507
|
+
* Log authentication events
|
|
508
|
+
* @param user User involved in auth event
|
|
509
|
+
* @param action Auth action performed
|
|
510
|
+
* @param success Whether the auth action was successful
|
|
511
|
+
* @param additionalData Additional auth-related data
|
|
512
|
+
* @returns Observable with the audit log ID
|
|
513
|
+
*/
|
|
514
|
+
abstract logAuthEvent(user: User, action: AuditAction, success: boolean, additionalData?: Record<string, any>): Observable<string>;
|
|
515
|
+
/**
|
|
516
|
+
* Query audit logs with filters
|
|
517
|
+
* @param query Query filters
|
|
518
|
+
* @returns Observable with array of audit logs
|
|
519
|
+
*/
|
|
520
|
+
abstract queryLogs(query: AuditLogQuery): Observable<AuditLog[]>;
|
|
521
|
+
/**
|
|
522
|
+
* Get audit log statistics
|
|
523
|
+
* @param timeRange Optional time range for statistics
|
|
524
|
+
* @returns Observable with audit statistics
|
|
525
|
+
*/
|
|
526
|
+
abstract getStats(timeRange?: {
|
|
527
|
+
start: Date;
|
|
528
|
+
end: Date;
|
|
529
|
+
}): Observable<AuditLogStats>;
|
|
530
|
+
/**
|
|
531
|
+
* Get audit logs for a specific user
|
|
532
|
+
* @param userId User ID
|
|
533
|
+
* @param limit Optional limit on number of logs
|
|
534
|
+
* @returns Observable with array of user's audit logs
|
|
535
|
+
*/
|
|
536
|
+
abstract getUserLogs(userId: string, limit?: number): Observable<AuditLog[]>;
|
|
537
|
+
/**
|
|
538
|
+
* Get recent audit logs
|
|
539
|
+
* @param limit Number of recent logs to retrieve
|
|
540
|
+
* @returns Observable with array of recent audit logs
|
|
541
|
+
*/
|
|
542
|
+
abstract getRecentLogs(limit?: number): Observable<AuditLog[]>;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
interface AuthResult<T = any> {
|
|
546
|
+
data?: T;
|
|
547
|
+
error?: {
|
|
548
|
+
code: AuthErrorCode;
|
|
549
|
+
message: string;
|
|
550
|
+
};
|
|
551
|
+
success: boolean;
|
|
552
|
+
}
|
|
553
|
+
interface AuthState {
|
|
554
|
+
error: string | null;
|
|
555
|
+
isAuthenticated: boolean;
|
|
556
|
+
loading: boolean;
|
|
557
|
+
user: AuthUser | null;
|
|
558
|
+
}
|
|
559
|
+
interface AuthUser {
|
|
560
|
+
createdAt?: string;
|
|
561
|
+
customClaims?: Record<string, any>;
|
|
562
|
+
displayName: string | null;
|
|
563
|
+
email: string | null;
|
|
564
|
+
emailVerified: boolean;
|
|
565
|
+
lastSignInAt?: string;
|
|
566
|
+
phoneNumber: string | null;
|
|
567
|
+
photoURL: string | null;
|
|
568
|
+
uid: string;
|
|
569
|
+
}
|
|
570
|
+
interface EmailPasswordCredentials {
|
|
571
|
+
email: string;
|
|
572
|
+
password: string;
|
|
573
|
+
}
|
|
574
|
+
interface UserRegistrationData extends EmailPasswordCredentials {
|
|
575
|
+
displayName?: string;
|
|
576
|
+
phoneNumber?: string;
|
|
577
|
+
}
|
|
578
|
+
type AuthCredentials = EmailPasswordCredentials;
|
|
579
|
+
type AuthErrorCode = 'auth/user-not-found' | 'auth/wrong-password' | 'auth/email-already-in-use' | 'auth/weak-password' | 'auth/invalid-email' | 'auth/user-disabled' | 'auth/too-many-requests' | 'auth/network-request-failed' | 'auth/popup-closed-by-user' | 'auth/popup-blocked' | 'auth/cancelled-popup-request' | 'auth/account-exists-with-different-credential' | 'unknown-error';
|
|
580
|
+
type AuthMethod = 'signIn' | 'signUp' | 'signOut' | 'resetPassword' | 'verifyEmail';
|
|
581
|
+
type AuthProvider = 'email' | 'google' | 'facebook';
|
|
582
|
+
declare const initialAuthState: AuthState;
|
|
583
|
+
|
|
584
|
+
declare abstract class AuthenticationStoreService {
|
|
585
|
+
abstract signOut(): Promise<AuthResult<void>>;
|
|
586
|
+
abstract signInWithEmailAndPassword(email: string, password: string): Promise<void>;
|
|
587
|
+
abstract signInWithGoogle(): Promise<AuthResult<AuthUser>>;
|
|
588
|
+
abstract createUserWithEmailAndPassword(userData: UserRegistrationData): Promise<AuthResult<AuthUser>>;
|
|
589
|
+
abstract sendPasswordResetEmail(email: string): Promise<void>;
|
|
590
|
+
abstract updatePassword(newPassword: string): Promise<AuthResult<void>>;
|
|
591
|
+
abstract updateEmail(newEmail: string): Promise<AuthResult<void>>;
|
|
592
|
+
abstract getIdToken(forceRefresh: boolean): Promise<string | null>;
|
|
593
|
+
abstract getStore(): AuthenticationStoreView;
|
|
594
|
+
}
|
|
595
|
+
interface AuthenticationStoreView {
|
|
596
|
+
user: Signal<AuthUser | null>;
|
|
597
|
+
isAuthenticated: Signal<boolean>;
|
|
598
|
+
isLoading: Signal<boolean>;
|
|
599
|
+
error: Signal<string | null>;
|
|
600
|
+
isLoggedIn: Signal<boolean>;
|
|
601
|
+
userDisplayName: Signal<string>;
|
|
602
|
+
userInitials: Signal<string>;
|
|
603
|
+
setUser(user: AuthUser | null): void;
|
|
604
|
+
setLoading(isLoading: boolean): void;
|
|
605
|
+
setError(error: string | null): void;
|
|
606
|
+
clearError(): void;
|
|
607
|
+
clearUser(): void;
|
|
608
|
+
setInitialized(): void;
|
|
609
|
+
}
|
|
610
|
+
declare const AUTHENTICATION_STORE_SERVICE_TOKEN: InjectionToken<AuthenticationStoreService>;
|
|
611
|
+
declare const AUTHENTICATION_STORE_VIEW_TOKEN: InjectionToken<AuthenticationStoreView>;
|
|
612
|
+
|
|
613
|
+
declare abstract class AuthenticationService {
|
|
614
|
+
private readonly _authState;
|
|
615
|
+
readonly authState: _angular_core.Signal<AuthState>;
|
|
616
|
+
readonly currentUser: _angular_core.Signal<AuthState>;
|
|
617
|
+
readonly isAuthenticated: _angular_core.Signal<AuthState>;
|
|
618
|
+
abstract createUserWithEmailAndPassword(userData: UserRegistrationData): Promise<AuthResult<AuthUser>>;
|
|
619
|
+
abstract generateUserWithUID(email: string, displayName?: string): Promise<AuthResult<AuthUser>>;
|
|
620
|
+
abstract generateUserWithUIDAndSendReset(email: string, displayName?: string): Promise<AuthResult<AuthUser>>;
|
|
621
|
+
abstract getIdToken(forceRefresh: boolean): Promise<string | null>;
|
|
622
|
+
abstract getIdTokenResult(forceRefresh: boolean): Promise<any>;
|
|
623
|
+
abstract sendEmailVerification(): Promise<AuthResult<void>>;
|
|
624
|
+
abstract sendPasswordResetEmail(email: string): Promise<void>;
|
|
625
|
+
abstract signInWithEmailAndPassword(credentials: EmailPasswordCredentials): Promise<void>;
|
|
626
|
+
abstract signInWithGoogle(): Promise<AuthResult<AuthUser>>;
|
|
627
|
+
abstract signOut(): Promise<AuthResult<void>>;
|
|
628
|
+
abstract updateEmail(newEmail: string): Promise<AuthResult<void>>;
|
|
629
|
+
abstract updatePassword(newPassword: string): Promise<AuthResult<void>>;
|
|
630
|
+
abstract updateProfile(profile: Partial<Pick<AuthUser, 'displayName' | 'photoURL'>>): Promise<AuthResult<void>>;
|
|
631
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AuthenticationService, never>;
|
|
632
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AuthenticationService>;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
declare const DEFAULT_FIREBASE_CONFIG: FirebaseConfig;
|
|
636
|
+
declare const DEFAULT_FIREBASE_AUTH_CONFIG: FirebaseAuthConfig;
|
|
637
|
+
interface FirebaseConfig {
|
|
638
|
+
apiKey: string;
|
|
639
|
+
authDomain: string;
|
|
640
|
+
projectId: string;
|
|
641
|
+
storageBucket: string;
|
|
642
|
+
messagingSenderId: string;
|
|
643
|
+
appId: string;
|
|
644
|
+
measurementId?: string;
|
|
645
|
+
}
|
|
646
|
+
interface SessionConfig {
|
|
647
|
+
/** Inactivity timeout in milliseconds (default: 30 minutes) */
|
|
648
|
+
inactivityTimeout: number;
|
|
649
|
+
/** Warning before timeout in milliseconds (default: 5 minutes before timeout) */
|
|
650
|
+
warningBeforeTimeout?: number;
|
|
651
|
+
/** Events to track for activity (default: ['click', 'keypress', 'mousemove', 'touchstart']) */
|
|
652
|
+
events?: string[];
|
|
653
|
+
/** Whether to show warning dialog before logout */
|
|
654
|
+
showWarningDialog?: boolean;
|
|
655
|
+
}
|
|
656
|
+
interface UserConfig {
|
|
657
|
+
/** Firestore collection name for user documents (default: 'user') */
|
|
658
|
+
collection?: string;
|
|
659
|
+
/** Default role ID to assign to new OAuth users */
|
|
660
|
+
defaultRoleId: string;
|
|
661
|
+
/** Whether to automatically create user document on OAuth login (default: true) */
|
|
662
|
+
autoCreate?: boolean;
|
|
663
|
+
}
|
|
664
|
+
interface FirebaseAuthConfig {
|
|
665
|
+
firebase: FirebaseConfig;
|
|
666
|
+
enableRegistration?: boolean;
|
|
667
|
+
enableSocialLogin?: boolean;
|
|
668
|
+
enabledProviders?: ('email' | 'google' | 'facebook')[];
|
|
669
|
+
session?: SessionConfig;
|
|
670
|
+
/** Configuration for automatic user document creation on OAuth login */
|
|
671
|
+
userDocument?: UserConfig;
|
|
672
|
+
}
|
|
673
|
+
declare const FIREBASE_CONFIG: InjectionToken<FirebaseConfig>;
|
|
674
|
+
declare const FIREBASE_AUTH_CONFIG: InjectionToken<FirebaseAuthConfig>;
|
|
675
|
+
declare function provideFirebaseAuthConfig(config: FirebaseAuthConfig): Provider;
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Represents a permission in the authorization system
|
|
679
|
+
*/
|
|
680
|
+
interface Permission {
|
|
681
|
+
/**
|
|
682
|
+
* Unique identifier for the permission
|
|
683
|
+
*/
|
|
684
|
+
id: string;
|
|
685
|
+
/**
|
|
686
|
+
* Human-readable name of the permission
|
|
687
|
+
*/
|
|
688
|
+
name: string;
|
|
689
|
+
/**
|
|
690
|
+
* Optional description of what this permission allows
|
|
691
|
+
*/
|
|
692
|
+
description?: string;
|
|
693
|
+
/**
|
|
694
|
+
* Optional category to group related permissions
|
|
695
|
+
*/
|
|
696
|
+
category?: string;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Represents a role that can be assigned to users
|
|
700
|
+
*/
|
|
701
|
+
interface Role {
|
|
702
|
+
/**
|
|
703
|
+
* Unique identifier for the role
|
|
704
|
+
*/
|
|
705
|
+
id: string;
|
|
706
|
+
/**
|
|
707
|
+
* Human-readable name of the role
|
|
708
|
+
*/
|
|
709
|
+
name: string;
|
|
710
|
+
/**
|
|
711
|
+
* Optional description of the role's purpose
|
|
712
|
+
*/
|
|
713
|
+
description?: string;
|
|
714
|
+
/**
|
|
715
|
+
* List of permission IDs granted to this role
|
|
716
|
+
*/
|
|
717
|
+
permissions: string[];
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Represents authorization context for a user
|
|
721
|
+
*/
|
|
722
|
+
interface AuthorizationContext {
|
|
723
|
+
/**
|
|
724
|
+
* User's assigned roles
|
|
725
|
+
*/
|
|
726
|
+
roles: Role[];
|
|
727
|
+
/**
|
|
728
|
+
* Direct permissions assigned to the user (not through roles)
|
|
729
|
+
*/
|
|
730
|
+
directPermissions: Permission[];
|
|
731
|
+
/**
|
|
732
|
+
* Additional context data that might affect authorization decisions
|
|
733
|
+
*/
|
|
734
|
+
context?: Record<string, any>;
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Configuration options for authorization checks
|
|
738
|
+
*/
|
|
739
|
+
interface AuthorizationOptions {
|
|
740
|
+
/**
|
|
741
|
+
* Whether to require ALL permissions (AND logic) or ANY permission (OR logic)
|
|
742
|
+
* @default 'any'
|
|
743
|
+
*/
|
|
744
|
+
mode?: 'all' | 'any';
|
|
745
|
+
/**
|
|
746
|
+
* Whether to include permissions from roles
|
|
747
|
+
* @default true
|
|
748
|
+
*/
|
|
749
|
+
includeRolePermissions?: boolean;
|
|
750
|
+
/**
|
|
751
|
+
* Whether to include direct permissions
|
|
752
|
+
* @default true
|
|
753
|
+
*/
|
|
754
|
+
includeDirectPermissions?: boolean;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
interface CloudFunctionResult<T = any> {
|
|
758
|
+
success: boolean;
|
|
759
|
+
message?: string;
|
|
760
|
+
data?: T;
|
|
761
|
+
userId?: string;
|
|
762
|
+
uid?: string;
|
|
763
|
+
userCreated?: boolean;
|
|
764
|
+
}
|
|
765
|
+
interface CreateUserAndSendPasswordResetResult extends CloudFunctionResult {
|
|
766
|
+
uid: string;
|
|
767
|
+
userId: string;
|
|
768
|
+
}
|
|
769
|
+
type BootstrapStatusResult = CloudFunctionResult<{
|
|
770
|
+
isBootstrapped: boolean;
|
|
771
|
+
userCount?: number;
|
|
772
|
+
}>;
|
|
773
|
+
interface CreateUserRequest {
|
|
774
|
+
email: string;
|
|
775
|
+
password?: string;
|
|
776
|
+
firstName: string;
|
|
777
|
+
lastName: string;
|
|
778
|
+
displayName?: string;
|
|
779
|
+
phoneNumber?: string;
|
|
780
|
+
photoURL?: string;
|
|
781
|
+
disabled?: boolean;
|
|
782
|
+
sendWelcomeEmail?: boolean;
|
|
783
|
+
loginUrl?: string;
|
|
784
|
+
}
|
|
785
|
+
interface CreateUserResponse {
|
|
786
|
+
success: boolean;
|
|
787
|
+
uid: string;
|
|
788
|
+
email: string;
|
|
789
|
+
emailSent?: boolean;
|
|
790
|
+
error?: string;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
declare abstract class CloudService {
|
|
794
|
+
abstract checkBootstrapStatus(): Promise<BootstrapStatusResult>;
|
|
795
|
+
abstract createUserAndSendPasswordReset(email: string, displayName: string, sendEmail: boolean): Promise<CreateUserAndSendPasswordResetResult>;
|
|
796
|
+
abstract sendPasswordResetEmail(email: string): Promise<CloudFunctionResult>;
|
|
797
|
+
abstract sendWelcomeEmail(email: string, displayName: string, firstName?: string, lastName?: string, roles?: string[]): Promise<CloudFunctionResult>;
|
|
798
|
+
abstract systemBootstrap(adminEmail: string, adminDisplayName?: string, adminPassword?: string): Promise<CloudFunctionResult>;
|
|
799
|
+
abstract registerUserWithWelcomeEmail(email: string, password: string, firstName: string, lastName: string, options?: {
|
|
800
|
+
displayName?: string;
|
|
801
|
+
phoneNumber?: string;
|
|
802
|
+
photoURL?: string;
|
|
803
|
+
disabled?: boolean;
|
|
804
|
+
loginUrl?: string;
|
|
805
|
+
}): Promise<CreateUserResponse>;
|
|
806
|
+
abstract registerUserWithoutEmail(email: string, password: string, firstName: string, lastName: string, options?: {
|
|
807
|
+
displayName?: string;
|
|
808
|
+
phoneNumber?: string;
|
|
809
|
+
photoURL?: string;
|
|
810
|
+
disabled?: boolean;
|
|
811
|
+
}): Promise<CreateUserResponse>;
|
|
812
|
+
abstract generateThumbnail(params: {
|
|
813
|
+
path: string;
|
|
814
|
+
documentId?: string;
|
|
815
|
+
maxWidth?: number;
|
|
816
|
+
maxHeight?: number;
|
|
817
|
+
force?: boolean;
|
|
818
|
+
}): Promise<CloudFunctionResult & {
|
|
819
|
+
thumbPath?: string;
|
|
820
|
+
documentUpdated?: boolean;
|
|
821
|
+
originalFilePath?: string;
|
|
822
|
+
}>;
|
|
823
|
+
}
|
|
824
|
+
declare const CLOUD_SERVICE_TOKEN: InjectionToken<CloudService>;
|
|
825
|
+
|
|
826
|
+
type AppBootstrapConfig = {
|
|
827
|
+
bootstrapAdmin: {
|
|
828
|
+
email: string;
|
|
829
|
+
displayName: string;
|
|
830
|
+
firstName: string;
|
|
831
|
+
lastName: string;
|
|
832
|
+
language: string;
|
|
833
|
+
roles: string[];
|
|
834
|
+
};
|
|
835
|
+
};
|
|
836
|
+
declare const APP_BOOTSTRAP_CONFIG: InjectionToken<AppBootstrapConfig>;
|
|
837
|
+
declare function provideAppBootstrapConfig(config: AppBootstrapConfig): Provider;
|
|
838
|
+
declare const DEFAULT_APP_BOOTSTRAP_CONFIG: AppBootstrapConfig;
|
|
839
|
+
|
|
840
|
+
declare const DOCUMENTS_KEYS: {
|
|
841
|
+
ház: string;
|
|
842
|
+
hálószoba: string;
|
|
843
|
+
földszint: string;
|
|
844
|
+
emelet: string;
|
|
845
|
+
nappali: string;
|
|
846
|
+
étkező: string;
|
|
847
|
+
konyha: string;
|
|
848
|
+
fürdőszoba: string;
|
|
849
|
+
kültér: string;
|
|
850
|
+
stég: string;
|
|
851
|
+
parkoló: string;
|
|
852
|
+
bográcsozó: string;
|
|
853
|
+
terasz: string;
|
|
854
|
+
wc: string;
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
interface NotificationConfig {
|
|
858
|
+
closable?: boolean;
|
|
859
|
+
life?: number;
|
|
860
|
+
sticky?: boolean;
|
|
861
|
+
}
|
|
862
|
+
declare const NOTIFICATION_CONFIG_TOKEN: InjectionToken<NotificationConfig>;
|
|
863
|
+
declare function provideNotificationConfig(config?: NotificationConfig): {
|
|
864
|
+
provide: InjectionToken<NotificationConfig>;
|
|
865
|
+
useValue: NotificationConfig;
|
|
866
|
+
};
|
|
867
|
+
declare const DEFAULT_NOTIFICATION_CONFIG: NotificationConfig;
|
|
868
|
+
|
|
869
|
+
interface EmailConfig {
|
|
870
|
+
fromEmail: string;
|
|
871
|
+
fromName: string;
|
|
872
|
+
mailersendApiKey: string;
|
|
873
|
+
}
|
|
874
|
+
interface SendPasswordResetEmailData {
|
|
875
|
+
customMessage?: string;
|
|
876
|
+
email: string;
|
|
877
|
+
}
|
|
878
|
+
type CreateUserData = Omit<WelcomeEmailData, 'firstName' | 'lastName'> & {
|
|
879
|
+
sendEmail?: boolean;
|
|
880
|
+
};
|
|
881
|
+
type WelcomeEmailData = Omit<User, 'language' | 'phone' | 'photoUrl' | 'uid'> & {
|
|
882
|
+
roles?: string[];
|
|
883
|
+
temporaryPassword?: string;
|
|
884
|
+
};
|
|
885
|
+
type WelcomeEmailDataWithConfig = WelcomeEmailData & Omit<EmailConfig, 'mailersendApiKey'>;
|
|
886
|
+
declare const EMAIL_CONFIG: InjectionToken<EmailConfig>;
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* Email service for sending welcome and notification emails
|
|
890
|
+
* This can be implemented with different providers
|
|
891
|
+
*/
|
|
892
|
+
declare abstract class EmailService {
|
|
893
|
+
/**
|
|
894
|
+
* Send custom notification email
|
|
895
|
+
* @param to Recipient email
|
|
896
|
+
* @param subject Email subject
|
|
897
|
+
* @param body Email body (HTML or text)
|
|
898
|
+
* @param data Optional template data
|
|
899
|
+
* @returns Promise that resolves when email is sent
|
|
900
|
+
*/
|
|
901
|
+
abstract sendNotificationEmail(to: string, subject: string, body: string, data?: Record<string, any>): Promise<void>;
|
|
902
|
+
/**
|
|
903
|
+
* Send welcome email to newly created user
|
|
904
|
+
* @param userData User data for the email
|
|
905
|
+
* @returns Promise that resolves when email is sent
|
|
906
|
+
*/
|
|
907
|
+
abstract sendWelcomeEmail(userData: WelcomeEmailData): Promise<void>;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
declare enum ErrorType {
|
|
911
|
+
HttpError = "http-error"
|
|
912
|
+
}
|
|
913
|
+
interface ErrorOptions {
|
|
914
|
+
type: ErrorType;
|
|
915
|
+
viewable?: boolean;
|
|
916
|
+
}
|
|
917
|
+
declare class KError extends Error {
|
|
918
|
+
options: ErrorOptions;
|
|
919
|
+
constructor(message: string, error: Error, options: ErrorOptions);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
declare abstract class ErrorUtilService {
|
|
923
|
+
abstract createErrorMessage(error: KError): Message;
|
|
924
|
+
abstract throwEffectError(message: string, error: unknown, viewable?: boolean): KError;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
declare abstract class DateTimePipeBase implements PipeTransform {
|
|
928
|
+
abstract transform(value: any, ...args: unknown[]): string;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
declare abstract class DateUtil {
|
|
932
|
+
abstract createActionTime(minute: number, second: number): number;
|
|
933
|
+
abstract createFullTime(startTime: number, minute: number, second: number): number;
|
|
934
|
+
abstract getDateRange(firstDate: Date, lastDate: Date): Date[];
|
|
935
|
+
abstract getDateRangeWithoutBorder(firstDate: Date, lastDate: Date): Date[];
|
|
936
|
+
abstract getDateRangeAsString(dates: Date[], format: string): string[];
|
|
937
|
+
abstract getDateRangeLength(firstDate: Date, lastDate: Date): number;
|
|
938
|
+
abstract getFormattedDate(date: Date, format: string): string;
|
|
939
|
+
abstract getNextDay(baseDate: Date): Date;
|
|
940
|
+
abstract getNow(): number;
|
|
941
|
+
abstract getPreviousDay(baseDate: Date): Date;
|
|
942
|
+
abstract getToday(): Date;
|
|
943
|
+
abstract getTomorrow(): Date;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
declare interface HashMapModel<T = unknown> {
|
|
947
|
+
[key: string]: T;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
declare enum LanguagesEnum {
|
|
951
|
+
de = "de",
|
|
952
|
+
en = "en",
|
|
953
|
+
hu = "hu",
|
|
954
|
+
hr = "hr",
|
|
955
|
+
ro = "ro",
|
|
956
|
+
sk = "sk",
|
|
957
|
+
sl = "sl",
|
|
958
|
+
sr = "sr",
|
|
959
|
+
uk = "uk"
|
|
960
|
+
}
|
|
961
|
+
declare const LANGUAGES_TOKEN: InjectionToken<string[]>;
|
|
962
|
+
declare const DEFAULT_LANGUAGE_TOKEN: InjectionToken<string>;
|
|
963
|
+
|
|
964
|
+
type LoaderData = {
|
|
965
|
+
scope: string;
|
|
966
|
+
};
|
|
967
|
+
type I18nText = {
|
|
968
|
+
[key in string]: string;
|
|
969
|
+
};
|
|
970
|
+
interface I18nConfig {
|
|
971
|
+
availableLangs: LanguagesEnum[];
|
|
972
|
+
defaultLang: LanguagesEnum;
|
|
973
|
+
prodMode: boolean;
|
|
974
|
+
reRenderOnLangChange: boolean;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
declare abstract class I18nService {
|
|
978
|
+
protected httpClient: HttpClient;
|
|
979
|
+
protected defaultPath: string;
|
|
980
|
+
constructor(httpClient: HttpClient);
|
|
981
|
+
abstract activeLanguageChanges$(): Observable<string>;
|
|
982
|
+
abstract getActiveLang(): LanguagesEnum;
|
|
983
|
+
abstract getActiveLangAsString(): string;
|
|
984
|
+
abstract getAvailableLanguages(): string[];
|
|
985
|
+
abstract getActiveLocale(): string;
|
|
986
|
+
abstract getDefaultI18nText(): I18nText;
|
|
987
|
+
abstract getValue(property: any, locale?: string): string;
|
|
988
|
+
abstract getValueByLanguage(i18nText: I18nText, language?: string): string;
|
|
989
|
+
abstract init(language: string): void;
|
|
990
|
+
abstract load(): Observable<Translation>;
|
|
991
|
+
abstract localizeDate(date: string | Date, locale: string, format: DateFormatOptions): string;
|
|
992
|
+
abstract nameComponentShorter(firstName: string, lastName: string): string[];
|
|
993
|
+
abstract translate<T>(key: string | string[], params?: HashMapModel<unknown>, lang?: string): string;
|
|
994
|
+
abstract selectTranslate$(key: string, params?: HashMapModel<unknown>, lang?: string): Observable<string>;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
declare abstract class I18nUtil {
|
|
998
|
+
abstract getActiveLang(): LanguagesEnum;
|
|
999
|
+
abstract getDefaultI18nText(): I18nText;
|
|
1000
|
+
abstract updateLanguage(language: string): void;
|
|
1001
|
+
abstract getValueByLanguage(i18nText: I18nText, language?: string): string;
|
|
1002
|
+
abstract getCurrentLocale(): string;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
interface Localizable {
|
|
1006
|
+
currentLanguage: string;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
type IconType = 'material' | 'svg' | 'primeicons';
|
|
1010
|
+
type Icon = {
|
|
1011
|
+
name: string;
|
|
1012
|
+
class: string;
|
|
1013
|
+
type?: IconType;
|
|
1014
|
+
svgContent?: string;
|
|
1015
|
+
};
|
|
1016
|
+
/**
|
|
1017
|
+
* Helper function to create a PrimeIcons icon
|
|
1018
|
+
* @param name - PrimeIcons icon name without 'pi-' prefix (e.g., 'search', 'user', 'home')
|
|
1019
|
+
*/
|
|
1020
|
+
declare function primeIcon(name: string): Icon;
|
|
1021
|
+
declare const materialIcons: Icon[];
|
|
1022
|
+
/**
|
|
1023
|
+
* Custom SVG icons for items not available in Material Symbols
|
|
1024
|
+
*/
|
|
1025
|
+
declare const customSvgIcons: Icon[];
|
|
1026
|
+
/**
|
|
1027
|
+
* All available icons (Material + Custom SVG)
|
|
1028
|
+
*/
|
|
1029
|
+
declare const allIcons: Icon[];
|
|
1030
|
+
|
|
1031
|
+
/**
|
|
1032
|
+
* Abstract interface for logging operations
|
|
1033
|
+
* This defines the contract for logging without implementation details
|
|
1034
|
+
*/
|
|
1035
|
+
declare abstract class Logger {
|
|
1036
|
+
/**
|
|
1037
|
+
* Set the current user for audit logging
|
|
1038
|
+
* @param user Current authenticated user
|
|
1039
|
+
*/
|
|
1040
|
+
abstract setCurrentUser(user: User | null): void;
|
|
1041
|
+
/**
|
|
1042
|
+
* Get the current user
|
|
1043
|
+
* @returns Current user or null
|
|
1044
|
+
*/
|
|
1045
|
+
abstract getCurrentUser(): User | null;
|
|
1046
|
+
/**
|
|
1047
|
+
* Log trace level message
|
|
1048
|
+
* @param message Log message
|
|
1049
|
+
* @param data Additional data
|
|
1050
|
+
* @param context Context information
|
|
1051
|
+
*/
|
|
1052
|
+
abstract trace(message: string, data?: any, context?: Record<string, any>): void;
|
|
1053
|
+
/**
|
|
1054
|
+
* Log debug level message
|
|
1055
|
+
* @param message Log message
|
|
1056
|
+
* @param data Additional data
|
|
1057
|
+
* @param context Context information
|
|
1058
|
+
*/
|
|
1059
|
+
abstract debug(message: string, data?: any, context?: Record<string, any>): void;
|
|
1060
|
+
/**
|
|
1061
|
+
* Log info level message
|
|
1062
|
+
* @param message Log message
|
|
1063
|
+
* @param data Additional data
|
|
1064
|
+
* @param context Context information
|
|
1065
|
+
*/
|
|
1066
|
+
abstract info(message: string, data?: any, context?: Record<string, any>): void;
|
|
1067
|
+
/**
|
|
1068
|
+
* Log warning level message
|
|
1069
|
+
* @param message Log message
|
|
1070
|
+
* @param data Additional data
|
|
1071
|
+
* @param context Context information
|
|
1072
|
+
*/
|
|
1073
|
+
abstract warn(message: string, data?: any, context?: Record<string, any>): void;
|
|
1074
|
+
/**
|
|
1075
|
+
* Log error level message
|
|
1076
|
+
* @param message Log message
|
|
1077
|
+
* @param data Additional data
|
|
1078
|
+
* @param context Context information
|
|
1079
|
+
*/
|
|
1080
|
+
abstract error(message: string, data?: any, context?: Record<string, any>): void;
|
|
1081
|
+
/**
|
|
1082
|
+
* Log fatal level message
|
|
1083
|
+
* @param message Log message
|
|
1084
|
+
* @param data Additional data
|
|
1085
|
+
* @param context Context information
|
|
1086
|
+
*/
|
|
1087
|
+
abstract fatal(message: string, data?: any, context?: Record<string, any>): void;
|
|
1088
|
+
/**
|
|
1089
|
+
* Audit user actions with automatic success/failure logging
|
|
1090
|
+
* @param action Action being performed
|
|
1091
|
+
* @param resource Resource being acted upon
|
|
1092
|
+
* @param success Whether the action was successful
|
|
1093
|
+
* @param data Additional action data
|
|
1094
|
+
* @param context Additional context
|
|
1095
|
+
*/
|
|
1096
|
+
abstract auditUserAction(action: AuditAction, resource: AuditResource, success: boolean, data?: any, context?: Record<string, any>): void;
|
|
1097
|
+
/**
|
|
1098
|
+
* Audit authentication events
|
|
1099
|
+
* @param user User involved in auth event
|
|
1100
|
+
* @param action Auth action performed
|
|
1101
|
+
* @param success Whether the auth action was successful
|
|
1102
|
+
* @param additionalData Additional auth-related data
|
|
1103
|
+
*/
|
|
1104
|
+
abstract auditAuthEvent(user: User, action: AuditAction, success: boolean, additionalData?: Record<string, any>): void;
|
|
1105
|
+
/**
|
|
1106
|
+
* Audit UI interactions
|
|
1107
|
+
* @param action UI action performed
|
|
1108
|
+
* @param component Component where action occurred
|
|
1109
|
+
* @param data Additional UI data
|
|
1110
|
+
* @param context Additional context
|
|
1111
|
+
*/
|
|
1112
|
+
abstract auditUIAction(action: string, component: string, data?: any, context?: Record<string, any>): void;
|
|
1113
|
+
/**
|
|
1114
|
+
* Audit data operations
|
|
1115
|
+
* @param operation Type of data operation
|
|
1116
|
+
* @param resourceType Type of resource
|
|
1117
|
+
* @param resourceId Resource identifier
|
|
1118
|
+
* @param success Whether operation was successful
|
|
1119
|
+
* @param data Additional operation data
|
|
1120
|
+
* @param context Additional context
|
|
1121
|
+
*/
|
|
1122
|
+
abstract auditDataOperation(operation: 'create' | 'read' | 'update' | 'delete', resourceType: string, resourceId?: string, success?: boolean, data?: any, context?: Record<string, any>): void;
|
|
1123
|
+
/**
|
|
1124
|
+
* Log user action for tracking
|
|
1125
|
+
* @param component Component where action occurred
|
|
1126
|
+
* @param action Action performed
|
|
1127
|
+
* @param data Additional action data
|
|
1128
|
+
*/
|
|
1129
|
+
abstract logUserAction(component: string, action: string, data?: any): void;
|
|
1130
|
+
/**
|
|
1131
|
+
* Log performance metrics
|
|
1132
|
+
* @param operation Operation being measured
|
|
1133
|
+
* @param duration Duration in milliseconds
|
|
1134
|
+
* @param component Component where operation occurred
|
|
1135
|
+
*/
|
|
1136
|
+
abstract logPerformance(operation: string, duration: number, component?: string): void;
|
|
1137
|
+
/**
|
|
1138
|
+
* Log HTTP requests
|
|
1139
|
+
* @param method HTTP method
|
|
1140
|
+
* @param url Request URL
|
|
1141
|
+
* @param status Response status code
|
|
1142
|
+
* @param duration Request duration in milliseconds
|
|
1143
|
+
*/
|
|
1144
|
+
abstract logHttpRequest(method: string, url: string, status: number, duration: number): void;
|
|
1145
|
+
abstract logComponentLifecycle(component: string, lifecycle: string): void;
|
|
1146
|
+
abstract logThemeChangeAudit(from: string, to: string): void;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
interface LoggerEnvironmentConfig {
|
|
1150
|
+
production: boolean;
|
|
1151
|
+
logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
1152
|
+
enableConsoleLogging?: boolean;
|
|
1153
|
+
enableStorageLogging?: boolean;
|
|
1154
|
+
maxStoredLogs?: number;
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Log levels for the logger
|
|
1158
|
+
*/
|
|
1159
|
+
type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
1160
|
+
interface LoggerConfig {
|
|
1161
|
+
level: LogLevel;
|
|
1162
|
+
environment: 'development' | 'production' | 'test';
|
|
1163
|
+
enableConsole: boolean;
|
|
1164
|
+
}
|
|
1165
|
+
interface LogEntry {
|
|
1166
|
+
timestamp: string;
|
|
1167
|
+
level: string;
|
|
1168
|
+
message: string;
|
|
1169
|
+
data?: any;
|
|
1170
|
+
component?: string;
|
|
1171
|
+
action?: string;
|
|
1172
|
+
}
|
|
1173
|
+
declare const LOGGER_ENVIRONMENT = "LOGGER_ENVIRONMENT";
|
|
1174
|
+
/**
|
|
1175
|
+
* Decorator options for method logging
|
|
1176
|
+
*/
|
|
1177
|
+
interface LogMethodOptions {
|
|
1178
|
+
/** Component name for logging context */
|
|
1179
|
+
component?: string;
|
|
1180
|
+
/** Log level to use */
|
|
1181
|
+
level?: 'trace' | 'debug' | 'info' | 'warn' | 'error';
|
|
1182
|
+
/** Whether to log method entry */
|
|
1183
|
+
logEntry?: boolean;
|
|
1184
|
+
/** Whether to log method exit */
|
|
1185
|
+
logExit?: boolean;
|
|
1186
|
+
/** Whether to log method duration */
|
|
1187
|
+
logDuration?: boolean;
|
|
1188
|
+
/** Additional context data */
|
|
1189
|
+
context?: Record<string, any>;
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Decorator options for user action logging
|
|
1193
|
+
*/
|
|
1194
|
+
interface LogUserActionOptions {
|
|
1195
|
+
/** Component name */
|
|
1196
|
+
component: string;
|
|
1197
|
+
/** Action name - if not provided, method name will be used */
|
|
1198
|
+
action?: string;
|
|
1199
|
+
/** Additional data extractor function */
|
|
1200
|
+
dataExtractor?: (args: any[]) => any;
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Decorator options for data operation auditing
|
|
1204
|
+
*/
|
|
1205
|
+
interface LogDataOperationOptions {
|
|
1206
|
+
/** Operation type */
|
|
1207
|
+
operation: 'create' | 'read' | 'update' | 'delete';
|
|
1208
|
+
/** Resource type */
|
|
1209
|
+
resourceType: string;
|
|
1210
|
+
/** Function to extract resource ID from method arguments */
|
|
1211
|
+
resourceIdExtractor?: (args: any[]) => string | undefined;
|
|
1212
|
+
/** Function to extract operation data from method arguments */
|
|
1213
|
+
dataExtractor?: (args: any[]) => any;
|
|
1214
|
+
/** Component name for context */
|
|
1215
|
+
component?: string;
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* Decorator options for UI action auditing
|
|
1219
|
+
*/
|
|
1220
|
+
interface LogUIActionOptions {
|
|
1221
|
+
/** Component name */
|
|
1222
|
+
component: string;
|
|
1223
|
+
/** Action name - if not provided, method name will be used */
|
|
1224
|
+
action?: string;
|
|
1225
|
+
/** Function to extract UI data from method arguments */
|
|
1226
|
+
dataExtractor?: (args: any[]) => any;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
interface StorageFile {
|
|
1230
|
+
name: string;
|
|
1231
|
+
path: string;
|
|
1232
|
+
size: number;
|
|
1233
|
+
contentType: string;
|
|
1234
|
+
lastModified: Date;
|
|
1235
|
+
downloadUrl?: string;
|
|
1236
|
+
}
|
|
1237
|
+
interface StorageUploadProgress {
|
|
1238
|
+
bytesTransferred: number;
|
|
1239
|
+
totalBytes: number;
|
|
1240
|
+
progress: number;
|
|
1241
|
+
state: 'running' | 'paused' | 'success' | 'canceled' | 'error';
|
|
1242
|
+
}
|
|
1243
|
+
interface StorageUploadOptions {
|
|
1244
|
+
contentType?: string;
|
|
1245
|
+
metadata?: Record<string, string>;
|
|
1246
|
+
onProgress?: (progress: StorageUploadProgress) => void;
|
|
1247
|
+
}
|
|
1248
|
+
interface StorageListOptions {
|
|
1249
|
+
maxResults?: number;
|
|
1250
|
+
pageToken?: string;
|
|
1251
|
+
prefix?: string;
|
|
1252
|
+
}
|
|
1253
|
+
interface StorageListResult {
|
|
1254
|
+
items: StorageFile[];
|
|
1255
|
+
nextPageToken?: string;
|
|
1256
|
+
prefixes: string[];
|
|
1257
|
+
}
|
|
1258
|
+
interface StorageDeleteOptions {
|
|
1259
|
+
recursive?: boolean;
|
|
1260
|
+
}
|
|
1261
|
+
type StorageError = {
|
|
1262
|
+
code: string;
|
|
1263
|
+
message: string;
|
|
1264
|
+
serverResponse?: unknown;
|
|
1265
|
+
};
|
|
1266
|
+
|
|
1267
|
+
declare abstract class StorageEngine {
|
|
1268
|
+
/**
|
|
1269
|
+
* Upload a file to storage
|
|
1270
|
+
*/
|
|
1271
|
+
abstract upload(path: string, file: File | Blob, options?: StorageUploadOptions): Observable<StorageFile>;
|
|
1272
|
+
/**
|
|
1273
|
+
* Download a file as blob
|
|
1274
|
+
*/
|
|
1275
|
+
abstract download(path: string): Observable<Blob>;
|
|
1276
|
+
/**
|
|
1277
|
+
* Get download URL for a file
|
|
1278
|
+
*/
|
|
1279
|
+
abstract getDownloadUrl(path: string): Observable<string>;
|
|
1280
|
+
/**
|
|
1281
|
+
* Get file metadata
|
|
1282
|
+
*/
|
|
1283
|
+
abstract getMetadata(path: string): Observable<StorageFile>;
|
|
1284
|
+
/**
|
|
1285
|
+
* List files in a directory
|
|
1286
|
+
*/
|
|
1287
|
+
abstract list(path: string, options?: StorageListOptions): Observable<StorageListResult>;
|
|
1288
|
+
/**
|
|
1289
|
+
* Delete a file or directory
|
|
1290
|
+
*/
|
|
1291
|
+
abstract delete(path: string, options?: StorageDeleteOptions): Observable<void>;
|
|
1292
|
+
/**
|
|
1293
|
+
* Check if file exists
|
|
1294
|
+
*/
|
|
1295
|
+
abstract exists(path: string): Observable<boolean>;
|
|
1296
|
+
/**
|
|
1297
|
+
* Copy a file
|
|
1298
|
+
*/
|
|
1299
|
+
abstract copy(sourcePath: string, destinationPath: string): Observable<StorageFile>;
|
|
1300
|
+
/**
|
|
1301
|
+
* Move a file
|
|
1302
|
+
*/
|
|
1303
|
+
abstract move(sourcePath: string, destinationPath: string): Observable<StorageFile>;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
type RuleTarget = {
|
|
1307
|
+
kind: 'DocRef';
|
|
1308
|
+
path: string;
|
|
1309
|
+
} | {
|
|
1310
|
+
kind: 'TypedId';
|
|
1311
|
+
type: string;
|
|
1312
|
+
id: string;
|
|
1313
|
+
} | {
|
|
1314
|
+
kind: 'Composite';
|
|
1315
|
+
parts: Array<RuleTarget>;
|
|
1316
|
+
};
|
|
1317
|
+
interface RuleEffectBase {
|
|
1318
|
+
type: string;
|
|
1319
|
+
payload?: unknown;
|
|
1320
|
+
}
|
|
1321
|
+
interface TimeAsDateRange {
|
|
1322
|
+
from: Date;
|
|
1323
|
+
to: Date;
|
|
1324
|
+
}
|
|
1325
|
+
interface TimeAsString {
|
|
1326
|
+
from: string;
|
|
1327
|
+
to: string;
|
|
1328
|
+
}
|
|
1329
|
+
interface RuleWhen {
|
|
1330
|
+
time?: TimeAsString | TimeAsDateRange;
|
|
1331
|
+
conditions?: RuleCondition[];
|
|
1332
|
+
}
|
|
1333
|
+
interface Rule<RT extends RuleTarget = RuleTarget, W extends RuleWhen = RuleWhen, E extends RuleEffectBase = RuleEffectBase> {
|
|
1334
|
+
description: I18nText;
|
|
1335
|
+
enabled: boolean;
|
|
1336
|
+
entityId: string;
|
|
1337
|
+
name: I18nText;
|
|
1338
|
+
priority: number;
|
|
1339
|
+
tags?: string[];
|
|
1340
|
+
target: RT;
|
|
1341
|
+
when: W;
|
|
1342
|
+
effect: E;
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Condition for when a rule should be evaluated
|
|
1346
|
+
*/
|
|
1347
|
+
interface RuleCondition {
|
|
1348
|
+
field: string;
|
|
1349
|
+
operator: 'eq' | 'neq' | 'in' | 'gte' | 'lte' | 'gt' | 'lt';
|
|
1350
|
+
value: unknown;
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Context for rule evaluation
|
|
1354
|
+
* Contains all information needed to evaluate rules
|
|
1355
|
+
*/
|
|
1356
|
+
interface RuleEvaluationContext<T = unknown> {
|
|
1357
|
+
startDate?: Date;
|
|
1358
|
+
endDate?: Date;
|
|
1359
|
+
entityId: string;
|
|
1360
|
+
entityType: string;
|
|
1361
|
+
additionalContext?: T;
|
|
1362
|
+
}
|
|
1363
|
+
/**
|
|
1364
|
+
* Result of rule evaluation
|
|
1365
|
+
*/
|
|
1366
|
+
interface RuleEvaluationResult<TResult = unknown> {
|
|
1367
|
+
appliedRules: Rule[];
|
|
1368
|
+
result: TResult;
|
|
1369
|
+
conflicts: RuleConflict[];
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Conflict between rules
|
|
1373
|
+
*/
|
|
1374
|
+
interface RuleConflict {
|
|
1375
|
+
rule1: Rule;
|
|
1376
|
+
rule2: Rule;
|
|
1377
|
+
conflictType: string;
|
|
1378
|
+
message: string;
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Validation error for rules
|
|
1382
|
+
*/
|
|
1383
|
+
interface RuleValidationError {
|
|
1384
|
+
ruleId: string;
|
|
1385
|
+
field: string;
|
|
1386
|
+
message: string;
|
|
1387
|
+
conflictingRuleId?: string;
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Validation result
|
|
1391
|
+
*/
|
|
1392
|
+
interface RuleValidationResult {
|
|
1393
|
+
valid: boolean;
|
|
1394
|
+
errors: RuleValidationError[];
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
/**
|
|
1398
|
+
* Workflow Type Definitions
|
|
1399
|
+
*
|
|
1400
|
+
* These are the core workflow types used by entities that participate in workflows.
|
|
1401
|
+
* The actual workflow engine and services are in the 'workflow' library.
|
|
1402
|
+
*/
|
|
1403
|
+
|
|
1404
|
+
type WorkflowId = string;
|
|
1405
|
+
type StateId = string;
|
|
1406
|
+
type TransitionId = string;
|
|
1407
|
+
/**
|
|
1408
|
+
* Workflow summary stored in the parent entity (e.g., BookingEntity).
|
|
1409
|
+
* Contains only the current state and metadata for efficient queries.
|
|
1410
|
+
* The full history is stored in the workflow_history subcollection.
|
|
1411
|
+
*/
|
|
1412
|
+
interface WorkflowSummary {
|
|
1413
|
+
workflowDefinitionId: WorkflowId;
|
|
1414
|
+
currentState: StateId;
|
|
1415
|
+
initialState: StateId;
|
|
1416
|
+
stateCount: number;
|
|
1417
|
+
lastTransitionAt: string;
|
|
1418
|
+
lastTransitionBy: string;
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Interface for entities that can participate in workflows.
|
|
1422
|
+
* Extend your entity with this interface to make it workflowable.
|
|
1423
|
+
*
|
|
1424
|
+
* @example
|
|
1425
|
+
* ```typescript
|
|
1426
|
+
* interface BookingEntity extends Entity, Workflowable {
|
|
1427
|
+
* // ... booking fields
|
|
1428
|
+
* }
|
|
1429
|
+
* ```
|
|
1430
|
+
*/
|
|
1431
|
+
interface Workflowable {
|
|
1432
|
+
workflow?: WorkflowSummary;
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Type helper for entities that require workflow to be present.
|
|
1436
|
+
*/
|
|
1437
|
+
type WithWorkflow<T extends Workflowable> = T & {
|
|
1438
|
+
workflow: WorkflowSummary;
|
|
1439
|
+
};
|
|
1440
|
+
/**
|
|
1441
|
+
* Core data fields for a workflow history entry (without Entity base fields).
|
|
1442
|
+
*/
|
|
1443
|
+
interface WorkflowHistoryEntryData {
|
|
1444
|
+
bookingId: string;
|
|
1445
|
+
sequence: number;
|
|
1446
|
+
from: StateId;
|
|
1447
|
+
to: StateId;
|
|
1448
|
+
transitionId: TransitionId;
|
|
1449
|
+
changedBy: string;
|
|
1450
|
+
changedAt: string;
|
|
1451
|
+
comment?: string;
|
|
1452
|
+
payload?: unknown;
|
|
1453
|
+
}
|
|
1454
|
+
declare const WORKFLOW_HISTORY_FEATURE_KEY = "workflow_history";
|
|
1455
|
+
/**
|
|
1456
|
+
* Workflow history entry entity stored in the subcollection.
|
|
1457
|
+
* Extends Entity to include uid and meta for Firestore compatibility.
|
|
1458
|
+
*/
|
|
1459
|
+
interface WorkflowHistoryEntry extends Entity, WorkflowHistoryEntryData {
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Type for adding a new workflow history entry.
|
|
1463
|
+
* uid is auto-generated, meta is provided by the caller.
|
|
1464
|
+
*/
|
|
1465
|
+
type WorkflowHistoryEntryAdd = EntityAdd & WorkflowHistoryEntryData;
|
|
1466
|
+
/**
|
|
1467
|
+
* Type for updating workflow history entries.
|
|
1468
|
+
* NOTE: Updates are NOT allowed - this type exists only for type system compatibility.
|
|
1469
|
+
*/
|
|
1470
|
+
type WorkflowHistoryEntryUpdate = EntityUpdate & Partial<WorkflowHistoryEntryData>;
|
|
1471
|
+
/**
|
|
1472
|
+
* Model types for Firestore storage.
|
|
1473
|
+
*/
|
|
1474
|
+
type WorkflowHistoryModel = WorkflowHistoryEntry;
|
|
1475
|
+
type WorkflowHistoryModelAdd = WorkflowHistoryEntryAdd;
|
|
1476
|
+
|
|
1477
|
+
/**
|
|
1478
|
+
* Abstract WorkflowEngine - defines the contract for workflow operations
|
|
1479
|
+
*
|
|
1480
|
+
* Implementations should handle:
|
|
1481
|
+
* - Transition execution with guards and actions
|
|
1482
|
+
* - Permission and role checking
|
|
1483
|
+
* - Workflow history management
|
|
1484
|
+
*/
|
|
1485
|
+
|
|
1486
|
+
/**
|
|
1487
|
+
* Current user context for workflow operations
|
|
1488
|
+
*/
|
|
1489
|
+
interface WorkflowCurrentUser {
|
|
1490
|
+
id: string;
|
|
1491
|
+
roles: string[];
|
|
1492
|
+
permissions: string[];
|
|
1493
|
+
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Result of checking if a transition can be executed
|
|
1496
|
+
*/
|
|
1497
|
+
interface CanExecuteTransitionResult {
|
|
1498
|
+
allowed: boolean;
|
|
1499
|
+
reason?: string;
|
|
1500
|
+
failedCheck?: 'state' | 'permission' | 'role' | 'guard';
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Result of bulk transition execution
|
|
1504
|
+
*/
|
|
1505
|
+
interface BulkTransitionResult<T extends Workflowable> {
|
|
1506
|
+
succeeded: WithWorkflow<T>[];
|
|
1507
|
+
failed: Array<{
|
|
1508
|
+
entity: WithWorkflow<T>;
|
|
1509
|
+
error: string;
|
|
1510
|
+
}>;
|
|
1511
|
+
stats: {
|
|
1512
|
+
total: number;
|
|
1513
|
+
succeeded: number;
|
|
1514
|
+
failed: number;
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Workflow state definition
|
|
1519
|
+
*/
|
|
1520
|
+
interface WorkflowState {
|
|
1521
|
+
id: string;
|
|
1522
|
+
label: string;
|
|
1523
|
+
description?: string;
|
|
1524
|
+
isInitial?: boolean;
|
|
1525
|
+
isFinal?: boolean;
|
|
1526
|
+
color?: string;
|
|
1527
|
+
icon?: string;
|
|
1528
|
+
requiredFields?: string[];
|
|
1529
|
+
editableFields?: string[];
|
|
1530
|
+
readonlyFields?: string[];
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Workflow transition context passed to guards and actions
|
|
1534
|
+
*/
|
|
1535
|
+
interface WorkflowTransitionContext<T = unknown> {
|
|
1536
|
+
entity: T;
|
|
1537
|
+
currentUserId: string;
|
|
1538
|
+
currentUserRoles: string[];
|
|
1539
|
+
currentUserPermissions: string[];
|
|
1540
|
+
payload?: unknown;
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Guard function type - returns true if transition is allowed
|
|
1544
|
+
*/
|
|
1545
|
+
type WorkflowGuardFn<T = unknown> = (ctx: WorkflowTransitionContext<T>) => boolean | Promise<boolean>;
|
|
1546
|
+
/**
|
|
1547
|
+
* Action function type - executed after successful transition
|
|
1548
|
+
*/
|
|
1549
|
+
type WorkflowActionFn<T = unknown> = (ctx: WorkflowTransitionContext<T>) => void | Promise<void>;
|
|
1550
|
+
/**
|
|
1551
|
+
* Workflow transition definition
|
|
1552
|
+
*/
|
|
1553
|
+
interface WorkflowTransition<T = unknown> {
|
|
1554
|
+
id: string;
|
|
1555
|
+
from: string;
|
|
1556
|
+
to: string;
|
|
1557
|
+
label: string;
|
|
1558
|
+
description?: string;
|
|
1559
|
+
requiredPermissions?: string[];
|
|
1560
|
+
requiredRoles?: string[];
|
|
1561
|
+
guards?: WorkflowGuardFn<T>[];
|
|
1562
|
+
actions?: WorkflowActionFn<T>[];
|
|
1563
|
+
icon?: string;
|
|
1564
|
+
severity?: 'primary' | 'secondary' | 'success' | 'info' | 'warn' | 'danger' | 'help';
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* Complete workflow definition
|
|
1568
|
+
*/
|
|
1569
|
+
interface WorkflowDefinition<T = unknown> {
|
|
1570
|
+
id: string;
|
|
1571
|
+
entityType: string;
|
|
1572
|
+
label: string;
|
|
1573
|
+
description?: string;
|
|
1574
|
+
states: WorkflowState[];
|
|
1575
|
+
transitions: WorkflowTransition<T>[];
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Result of executing a transition - contains updated entity and history entry
|
|
1579
|
+
*/
|
|
1580
|
+
interface TransitionExecutionResult<T extends Workflowable> {
|
|
1581
|
+
entity: WithWorkflow<T>;
|
|
1582
|
+
historyEntry: WorkflowHistoryEntryData;
|
|
1583
|
+
}
|
|
1584
|
+
/**
|
|
1585
|
+
* Abstract WorkflowEngine class
|
|
1586
|
+
*
|
|
1587
|
+
* Defines the contract for workflow operations.
|
|
1588
|
+
* Implementations should be provided via dependency injection.
|
|
1589
|
+
*
|
|
1590
|
+
* @typeParam T - The entity type that extends Workflowable
|
|
1591
|
+
*/
|
|
1592
|
+
declare abstract class WorkflowEngine<T extends Workflowable> {
|
|
1593
|
+
/**
|
|
1594
|
+
* Check if a transition can be executed
|
|
1595
|
+
*/
|
|
1596
|
+
abstract canExecuteTransition(definition: WorkflowDefinition<T>, transitionId: TransitionId, entity: WithWorkflow<T>, currentUser: WorkflowCurrentUser): CanExecuteTransitionResult;
|
|
1597
|
+
/**
|
|
1598
|
+
* Execute a workflow transition
|
|
1599
|
+
* Returns both the updated entity and the history entry to be persisted
|
|
1600
|
+
*/
|
|
1601
|
+
abstract executeTransition(definition: WorkflowDefinition<T>, transitionId: TransitionId, entity: WithWorkflow<T>, currentUser: WorkflowCurrentUser, payload?: unknown, comment?: string): Promise<TransitionExecutionResult<T>>;
|
|
1602
|
+
/**
|
|
1603
|
+
* Execute transition on multiple entities
|
|
1604
|
+
*/
|
|
1605
|
+
abstract executeBulkTransition(definition: WorkflowDefinition<T>, transitionId: TransitionId, entities: WithWorkflow<T>[], currentUser: WorkflowCurrentUser, payload?: unknown): Promise<BulkTransitionResult<T>>;
|
|
1606
|
+
/**
|
|
1607
|
+
* Get available transitions from the current state
|
|
1608
|
+
*/
|
|
1609
|
+
abstract getAvailableTransitions(definition: WorkflowDefinition<T>, entity: WithWorkflow<T>, currentUser: WorkflowCurrentUser): WorkflowTransition<T>[];
|
|
1610
|
+
/**
|
|
1611
|
+
* Get the current state definition for an entity
|
|
1612
|
+
*/
|
|
1613
|
+
abstract getCurrentState(definition: WorkflowDefinition<T>, entity: WithWorkflow<T>): WorkflowState | undefined;
|
|
1614
|
+
/**
|
|
1615
|
+
* Get a state definition by ID
|
|
1616
|
+
*/
|
|
1617
|
+
abstract getState(definition: WorkflowDefinition<T>, stateId: StateId): WorkflowState | undefined;
|
|
1618
|
+
/**
|
|
1619
|
+
* Get the initial state for a workflow
|
|
1620
|
+
*/
|
|
1621
|
+
abstract getInitialState(definition: WorkflowDefinition<T>): WorkflowState | undefined;
|
|
1622
|
+
/**
|
|
1623
|
+
* Create initial workflow summary for a new entity
|
|
1624
|
+
*/
|
|
1625
|
+
abstract createInitialSummary(definition: WorkflowDefinition<T>, userId: string): WorkflowSummary;
|
|
1626
|
+
/**
|
|
1627
|
+
* Check if entity is in a final state
|
|
1628
|
+
*/
|
|
1629
|
+
abstract isFinalState(definition: WorkflowDefinition<T>, entity: WithWorkflow<T>): boolean;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
export { APP_BOOTSTRAP_CONFIG, AUDIT_FEATURE_KEY, AUTHENTICATION_STORE_SERVICE_TOKEN, AUTHENTICATION_STORE_VIEW_TOKEN, AuditService, AuthenticationService, AuthenticationStoreService, CLOUD_SERVICE_TOKEN, CloudService, DEFAULT_APP_BOOTSTRAP_CONFIG, DEFAULT_FIREBASE_AUTH_CONFIG, DEFAULT_FIREBASE_CONFIG, DEFAULT_LANGUAGE_TOKEN, DEFAULT_NOTIFICATION_CONFIG, DOCUMENTS_KEYS, DateTimePipeBase, DateUtil, EMAIL_CONFIG, EmailService, EntityAdapter, EntityEffect, EntityFormLogic, EntityRepository, ErrorType, ErrorUtilService, FIREBASE_AUTH_CONFIG, FIREBASE_CONFIG, FIRESTORE_ENGINE_CREATOR, I18nService, I18nUtil, KError, LANGUAGES_TOKEN, LOGGER_ENVIRONMENT, LanguagesEnum, Logger, NOTIFICATION_CONFIG_TOKEN, Repository, RepositoryEngine, StorageEngine, WORKFLOW_HISTORY_FEATURE_KEY, WorkflowEngine, allIcons, customSvgIcons, initialAuthState, materialIcons, primeIcon, provideAppBootstrapConfig, provideFirebaseAuthConfig, provideNotificationConfig };
|
|
1633
|
+
export type { AppBootstrapConfig, Audit, AuditAction, AuditEntity, AuditEntityAdd, AuditEntityUpdate, AuditLog, AuditLogQuery, AuditLogStats, AuditMetadata, AuditModel, AuditModelAdd, AuditModelUpdate, AuditResource, AuditResult, AuthCredentials, AuthErrorCode, AuthMethod, AuthProvider, AuthResult, AuthState, AuthUser, AuthenticationStoreView, AuthorizationContext, AuthorizationOptions, BatchOperation, BootstrapStatusResult, BulkTransitionResult, CanExecuteTransitionResult, CloudFunctionResult, CollectionPathBuilder, CreateUserAndSendPasswordResetResult, CreateUserData, CreateUserRequest, CreateUserResponse, CustomEntityState, EmailConfig, EmailPasswordCredentials, Entity, EntityActions, EntityAdd, EntityCollectionStoreView, EntityConfig, EntityFormStoreView, EntityHelper, EntityModel, EntityModelAdd, EntityModelUpdate, EntitySignals, EntityStore, EntityStoreView, EntityTableResourceStoreView, EntityTableStoreView, EntityType, EntityUpdate, ErrorOptions, FirebaseAuthConfig, FirebaseConfig, HashMapModel, I18nConfig, I18nText, Icon, IconType, LoaderData, Localizable, LogDataOperationOptions, LogEntry, LogLevel, LogMethodOptions, LogUIActionOptions, LogUserActionOptions, LoggerConfig, LoggerEnvironmentConfig, NotificationConfig, Permission, RepositoryEngineCreator, Role, Rule, RuleCondition, RuleConflict, RuleEffectBase, RuleEvaluationContext, RuleEvaluationResult, RuleTarget, RuleValidationError, RuleValidationResult, RuleWhen, RxEntityActions, SendPasswordResetEmailData, SessionConfig, StateId, StorageDeleteOptions, StorageError, StorageFile, StorageListOptions, StorageListResult, StorageUploadOptions, StorageUploadProgress, SubcollectionContext, TimeAsDateRange, TimeAsString, TransitionExecutionResult, TransitionId, UserConfig, UserRegistrationData, WelcomeEmailData, WelcomeEmailDataWithConfig, WithWorkflow, WorkflowActionFn, WorkflowCurrentUser, WorkflowDefinition, WorkflowGuardFn, WorkflowHistoryEntry, WorkflowHistoryEntryAdd, WorkflowHistoryEntryData, WorkflowHistoryEntryUpdate, WorkflowHistoryModel, WorkflowHistoryModelAdd, WorkflowId, WorkflowState, WorkflowSummary, WorkflowTransition, WorkflowTransitionContext, Workflowable };
|