@honuware/ui 0.1.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 +78 -0
- package/fesm2022/honuware-ui-access.mjs +557 -0
- package/fesm2022/honuware-ui-access.mjs.map +1 -0
- package/fesm2022/honuware-ui-auth.mjs +503 -0
- package/fesm2022/honuware-ui-auth.mjs.map +1 -0
- package/fesm2022/honuware-ui-controls.mjs +624 -0
- package/fesm2022/honuware-ui-controls.mjs.map +1 -0
- package/fesm2022/honuware-ui-crud.mjs +1101 -0
- package/fesm2022/honuware-ui-crud.mjs.map +1 -0
- package/fesm2022/honuware-ui-foundation.mjs +745 -0
- package/fesm2022/honuware-ui-foundation.mjs.map +1 -0
- package/fesm2022/honuware-ui-photos.mjs +238 -0
- package/fesm2022/honuware-ui-photos.mjs.map +1 -0
- package/fesm2022/honuware-ui-square.mjs +128 -0
- package/fesm2022/honuware-ui-square.mjs.map +1 -0
- package/fesm2022/honuware-ui-testing.mjs +325 -0
- package/fesm2022/honuware-ui-testing.mjs.map +1 -0
- package/fesm2022/honuware-ui.mjs +17 -0
- package/fesm2022/honuware-ui.mjs.map +1 -0
- package/package.json +80 -0
- package/types/honuware-ui-access.d.ts +382 -0
- package/types/honuware-ui-auth.d.ts +164 -0
- package/types/honuware-ui-controls.d.ts +136 -0
- package/types/honuware-ui-crud.d.ts +287 -0
- package/types/honuware-ui-foundation.d.ts +89 -0
- package/types/honuware-ui-photos.d.ts +46 -0
- package/types/honuware-ui-square.d.ts +65 -0
- package/types/honuware-ui-testing.d.ts +126 -0
- package/types/honuware-ui.d.ts +3 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { InjectionToken, Provider } from '@angular/core';
|
|
4
|
+
import { HttpClient, HttpErrorResponse, HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
|
|
5
|
+
|
|
6
|
+
interface DataResults {
|
|
7
|
+
sortedColumnNames: string[];
|
|
8
|
+
dataTable: string[][];
|
|
9
|
+
}
|
|
10
|
+
interface DataResultsWithCount extends DataResults {
|
|
11
|
+
totalCount: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ColumnDataInfo {
|
|
15
|
+
column_name: string;
|
|
16
|
+
type: string;
|
|
17
|
+
primary_key: boolean;
|
|
18
|
+
unique: boolean;
|
|
19
|
+
nullable: boolean;
|
|
20
|
+
column_friendly_name?: string;
|
|
21
|
+
label?: string;
|
|
22
|
+
hint?: string;
|
|
23
|
+
place_holder?: string;
|
|
24
|
+
regex?: string;
|
|
25
|
+
html_input_type?: string;
|
|
26
|
+
required?: boolean;
|
|
27
|
+
max_length?: number;
|
|
28
|
+
default_value?: string;
|
|
29
|
+
rows?: number;
|
|
30
|
+
hidden?: boolean;
|
|
31
|
+
readonly?: boolean;
|
|
32
|
+
enum_values?: string[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface ForeignKeyInfo {
|
|
36
|
+
column_name: string;
|
|
37
|
+
parent_column_name: string;
|
|
38
|
+
parent_table_name: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface TableSchema {
|
|
42
|
+
columns: ColumnDataInfo[];
|
|
43
|
+
description: string;
|
|
44
|
+
foreign_keys: ForeignKeyInfo[];
|
|
45
|
+
has_photo_support?: boolean;
|
|
46
|
+
primary_key: string;
|
|
47
|
+
table_friendly_name: string;
|
|
48
|
+
table_name: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface DatabaseSchema {
|
|
52
|
+
root_tables: string[];
|
|
53
|
+
nested_tables: string[];
|
|
54
|
+
tables: TableSchema[];
|
|
55
|
+
display_templates: Record<string, string>;
|
|
56
|
+
fk_picker_preload_threshold: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface FilterPair {
|
|
60
|
+
column_name: string;
|
|
61
|
+
column_value: string;
|
|
62
|
+
}
|
|
63
|
+
interface TableBinding {
|
|
64
|
+
tableName: string;
|
|
65
|
+
primaryKeyName: string;
|
|
66
|
+
primaryKeyValue: string;
|
|
67
|
+
}
|
|
68
|
+
interface FkOption {
|
|
69
|
+
value: string;
|
|
70
|
+
display: string;
|
|
71
|
+
}
|
|
72
|
+
interface FkOptionsResponse {
|
|
73
|
+
total_count: number;
|
|
74
|
+
options: FkOption[];
|
|
75
|
+
}
|
|
76
|
+
interface FkDisplayResponse {
|
|
77
|
+
resolved: Record<string, string>;
|
|
78
|
+
}
|
|
79
|
+
interface ComputedDateRule {
|
|
80
|
+
source: string;
|
|
81
|
+
dest: string;
|
|
82
|
+
offsetMinutes: number;
|
|
83
|
+
autoByDefault: boolean;
|
|
84
|
+
}
|
|
85
|
+
interface CrudFormAssist {
|
|
86
|
+
defaults?: Record<string, string>;
|
|
87
|
+
computedDates?: ComputedDateRule[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface AddItemBody {
|
|
91
|
+
table_name: string;
|
|
92
|
+
value: unknown;
|
|
93
|
+
}
|
|
94
|
+
interface UpdateItemBody {
|
|
95
|
+
table_name: string;
|
|
96
|
+
value: unknown;
|
|
97
|
+
column_name: string;
|
|
98
|
+
column_value: string;
|
|
99
|
+
}
|
|
100
|
+
interface CrudAccess {
|
|
101
|
+
addItem(body: AddItemBody): Observable<void>;
|
|
102
|
+
addItemFetchPrimaryKey(body: AddItemBody): Observable<string>;
|
|
103
|
+
getTableRows(tableName: string): Observable<DataResults>;
|
|
104
|
+
getRowsByColumn(tableName: string, columnName: string, ascending: boolean, pageSize: number, pageNumber: number): Observable<DataResultsWithCount>;
|
|
105
|
+
getFilteredTableRows(tableName: string, columnName: string, ascending: boolean, pageSize: number, page: number, filterPairs: FilterPair[]): Observable<DataResultsWithCount>;
|
|
106
|
+
getRow(tableName: string, columnName: string, columnValue: string): Observable<DataResults>;
|
|
107
|
+
getRowByValues(tableName: string, filterPairs: FilterPair[]): Observable<DataResults>;
|
|
108
|
+
updateItem(body: UpdateItemBody): Observable<void>;
|
|
109
|
+
deleteItem(tableName: string, columnName: string, columnValue: string): Observable<void>;
|
|
110
|
+
getDbSchema(): Observable<DatabaseSchema>;
|
|
111
|
+
getFkOptions(tableName: string, searchText: string, pageSize: number): Observable<FkOptionsResponse>;
|
|
112
|
+
resolveFkDisplay(parentTableName: string, values: string[]): Observable<FkDisplayResponse>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface UserInfo {
|
|
116
|
+
person_id: number;
|
|
117
|
+
first_name: string;
|
|
118
|
+
last_name: string;
|
|
119
|
+
email: string;
|
|
120
|
+
created_at: string;
|
|
121
|
+
roles: string[];
|
|
122
|
+
permissions: string[];
|
|
123
|
+
must_change_password?: boolean;
|
|
124
|
+
}
|
|
125
|
+
interface SetUserInfo {
|
|
126
|
+
first_name: string;
|
|
127
|
+
last_name: string;
|
|
128
|
+
email: string;
|
|
129
|
+
}
|
|
130
|
+
interface LoginInfo {
|
|
131
|
+
email: string;
|
|
132
|
+
password: string;
|
|
133
|
+
remember: boolean;
|
|
134
|
+
}
|
|
135
|
+
interface UpdateUserPasswordInfo {
|
|
136
|
+
old_password: string;
|
|
137
|
+
new_password: string;
|
|
138
|
+
}
|
|
139
|
+
interface AuthAccess {
|
|
140
|
+
register(firstName: string, lastName: string, email: string, password: string): Observable<void>;
|
|
141
|
+
verify(email: string, secret: string): Observable<void>;
|
|
142
|
+
login(loginInfo: LoginInfo): Observable<void>;
|
|
143
|
+
logout(): Observable<void>;
|
|
144
|
+
me(): Observable<void>;
|
|
145
|
+
remember(): Observable<void>;
|
|
146
|
+
getUserInfo(): Observable<UserInfo>;
|
|
147
|
+
setUserInfo(userInfo: SetUserInfo): Observable<void>;
|
|
148
|
+
updateUserPassword(passwordInfo: UpdateUserPasswordInfo): Observable<void>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface SourcePhotoInfo {
|
|
152
|
+
source_photo_id: number;
|
|
153
|
+
type: string;
|
|
154
|
+
width: number;
|
|
155
|
+
height: number;
|
|
156
|
+
created_at_us?: number;
|
|
157
|
+
}
|
|
158
|
+
interface HomePagePhotoInfo {
|
|
159
|
+
id: number;
|
|
160
|
+
title?: string;
|
|
161
|
+
description?: string;
|
|
162
|
+
created_at_us: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
interface PhotoAccess {
|
|
166
|
+
uploadPhoto(tableName: string, tableItemId: number, imageData: ArrayBuffer, imageType: string): Observable<SourcePhotoInfo>;
|
|
167
|
+
uploadUserPhoto(imageData: ArrayBuffer, imageType: string): Observable<SourcePhotoInfo>;
|
|
168
|
+
deletePhoto(tableName: string, tableItemId: number): Observable<void>;
|
|
169
|
+
hasPhoto(tableName: string, tableItemId: number): Observable<{
|
|
170
|
+
has_photo: boolean;
|
|
171
|
+
}>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
declare const HONUWARE_CRUD_ACCESS: InjectionToken<CrudAccess>;
|
|
175
|
+
declare const HONUWARE_AUTH_ACCESS: InjectionToken<AuthAccess>;
|
|
176
|
+
declare const HONUWARE_PHOTO_ACCESS: InjectionToken<PhotoAccess>;
|
|
177
|
+
interface HonuwareAccessConfig {
|
|
178
|
+
/**
|
|
179
|
+
* 'http' (default): wire the three tokens to the serializing proxy over the
|
|
180
|
+
* default HTTP implementations. 'mock': wire them to caller-supplied
|
|
181
|
+
* implementations (e.g. the in-memory mocks from @honuware/ui/testing).
|
|
182
|
+
*/
|
|
183
|
+
mode?: 'http' | 'mock';
|
|
184
|
+
crud?: CrudAccess;
|
|
185
|
+
auth?: AuthAccess;
|
|
186
|
+
photo?: PhotoAccess;
|
|
187
|
+
}
|
|
188
|
+
declare function provideHonuwareAccess(config?: HonuwareAccessConfig): Provider[];
|
|
189
|
+
|
|
190
|
+
declare const HONUWARE_API_BASE: InjectionToken<string>;
|
|
191
|
+
|
|
192
|
+
declare class CrudHttpAccess implements CrudAccess {
|
|
193
|
+
private http;
|
|
194
|
+
private base;
|
|
195
|
+
constructor(http: HttpClient, base: string);
|
|
196
|
+
addItem(body: AddItemBody): Observable<void>;
|
|
197
|
+
addItemFetchPrimaryKey(body: AddItemBody): Observable<string>;
|
|
198
|
+
getTableRows(tableName: string): Observable<DataResults>;
|
|
199
|
+
getRowsByColumn(tableName: string, columnName: string, ascending: boolean, pageSize: number, pageNumber: number): Observable<DataResultsWithCount>;
|
|
200
|
+
getFilteredTableRows(tableName: string, columnName: string, ascending: boolean, pageSize: number, page: number, filterPairs: FilterPair[]): Observable<DataResultsWithCount>;
|
|
201
|
+
getRow(tableName: string, columnName: string, columnValue: string): Observable<DataResults>;
|
|
202
|
+
getRowByValues(tableName: string, filterPairs: FilterPair[]): Observable<DataResults>;
|
|
203
|
+
updateItem(body: UpdateItemBody): Observable<void>;
|
|
204
|
+
deleteItem(tableName: string, columnName: string, columnValue: string): Observable<void>;
|
|
205
|
+
getDbSchema(): Observable<DatabaseSchema>;
|
|
206
|
+
getFkOptions(tableName: string, searchText: string, pageSize: number): Observable<FkOptionsResponse>;
|
|
207
|
+
resolveFkDisplay(parentTableName: string, values: string[]): Observable<FkDisplayResponse>;
|
|
208
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<CrudHttpAccess, never>;
|
|
209
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<CrudHttpAccess>;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
declare class AuthHttpAccess implements AuthAccess {
|
|
213
|
+
private http;
|
|
214
|
+
private base;
|
|
215
|
+
constructor(http: HttpClient, base: string);
|
|
216
|
+
register(firstName: string, lastName: string, email: string, password: string): Observable<void>;
|
|
217
|
+
verify(email: string, secret: string): Observable<void>;
|
|
218
|
+
login(loginInfo: LoginInfo): Observable<void>;
|
|
219
|
+
logout(): Observable<void>;
|
|
220
|
+
me(): Observable<void>;
|
|
221
|
+
remember(): Observable<void>;
|
|
222
|
+
getUserInfo(): Observable<UserInfo>;
|
|
223
|
+
setUserInfo(userInfo: SetUserInfo): Observable<void>;
|
|
224
|
+
updateUserPassword(passwordInfo: UpdateUserPasswordInfo): Observable<void>;
|
|
225
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AuthHttpAccess, never>;
|
|
226
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<AuthHttpAccess>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
declare class PhotoHttpAccess implements PhotoAccess {
|
|
230
|
+
private http;
|
|
231
|
+
private base;
|
|
232
|
+
constructor(http: HttpClient, base: string);
|
|
233
|
+
uploadPhoto(tableName: string, tableItemId: number, imageData: ArrayBuffer, imageType: string): Observable<SourcePhotoInfo>;
|
|
234
|
+
uploadUserPhoto(imageData: ArrayBuffer, imageType: string): Observable<SourcePhotoInfo>;
|
|
235
|
+
deletePhoto(tableName: string, tableItemId: number): Observable<void>;
|
|
236
|
+
hasPhoto(tableName: string, tableItemId: number): Observable<{
|
|
237
|
+
has_photo: boolean;
|
|
238
|
+
}>;
|
|
239
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<PhotoHttpAccess, never>;
|
|
240
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<PhotoHttpAccess>;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
declare class HonuwareAccessProxy implements CrudAccess, AuthAccess, PhotoAccess {
|
|
244
|
+
private crud;
|
|
245
|
+
private auth;
|
|
246
|
+
private photo;
|
|
247
|
+
private queue;
|
|
248
|
+
private busy;
|
|
249
|
+
constructor(crud: CrudHttpAccess, auth: AuthHttpAccess, photo: PhotoHttpAccess);
|
|
250
|
+
private serialize;
|
|
251
|
+
private pump;
|
|
252
|
+
addItem(body: AddItemBody): Observable<void>;
|
|
253
|
+
addItemFetchPrimaryKey(body: AddItemBody): Observable<string>;
|
|
254
|
+
getTableRows(tableName: string): Observable<DataResults>;
|
|
255
|
+
getRowsByColumn(t: string, c: string, a: boolean, s: number, p: number): Observable<DataResultsWithCount>;
|
|
256
|
+
getFilteredTableRows(t: string, c: string, a: boolean, s: number, p: number, f: FilterPair[]): Observable<DataResultsWithCount>;
|
|
257
|
+
getRow(t: string, c: string, v: string): Observable<DataResults>;
|
|
258
|
+
getRowByValues(t: string, f: FilterPair[]): Observable<DataResults>;
|
|
259
|
+
updateItem(body: UpdateItemBody): Observable<void>;
|
|
260
|
+
deleteItem(t: string, c: string, v: string): Observable<void>;
|
|
261
|
+
getDbSchema(): Observable<DatabaseSchema>;
|
|
262
|
+
getFkOptions(t: string, s: string, p: number): Observable<FkOptionsResponse>;
|
|
263
|
+
resolveFkDisplay(t: string, v: string[]): Observable<FkDisplayResponse>;
|
|
264
|
+
register(f: string, l: string, e: string, p: string): Observable<void>;
|
|
265
|
+
verify(email: string, secret: string): Observable<void>;
|
|
266
|
+
login(loginInfo: LoginInfo): Observable<void>;
|
|
267
|
+
logout(): Observable<void>;
|
|
268
|
+
me(): Observable<void>;
|
|
269
|
+
remember(): Observable<void>;
|
|
270
|
+
getUserInfo(): Observable<UserInfo>;
|
|
271
|
+
setUserInfo(userInfo: SetUserInfo): Observable<void>;
|
|
272
|
+
updateUserPassword(passwordInfo: UpdateUserPasswordInfo): Observable<void>;
|
|
273
|
+
uploadPhoto(t: string, id: number, data: ArrayBuffer, type: string): Observable<SourcePhotoInfo>;
|
|
274
|
+
uploadUserPhoto(data: ArrayBuffer, type: string): Observable<SourcePhotoInfo>;
|
|
275
|
+
deletePhoto(t: string, id: number): Observable<void>;
|
|
276
|
+
hasPhoto(t: string, id: number): Observable<{
|
|
277
|
+
has_photo: boolean;
|
|
278
|
+
}>;
|
|
279
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<HonuwareAccessProxy, never>;
|
|
280
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<HonuwareAccessProxy>;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
declare class PhotoUrlBuilder {
|
|
284
|
+
private apiBase;
|
|
285
|
+
constructor(apiBase: string);
|
|
286
|
+
scaledPhotoUrl(tableName: string, tableItemId: number | string, width: number, height: number): string;
|
|
287
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<PhotoUrlBuilder, never>;
|
|
288
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<PhotoUrlBuilder>;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* RFC 7807 Problem Details for HTTP APIs
|
|
293
|
+
* https://tools.ietf.org/html/rfc7807
|
|
294
|
+
*/
|
|
295
|
+
interface ProblemDetails {
|
|
296
|
+
/** Error type identifier (e.g., "validation_error") */
|
|
297
|
+
type: string;
|
|
298
|
+
/** Short human-readable summary */
|
|
299
|
+
title: string;
|
|
300
|
+
/** HTTP status code */
|
|
301
|
+
status: number;
|
|
302
|
+
/** Human-readable explanation for this specific occurrence */
|
|
303
|
+
detail: string;
|
|
304
|
+
/** URI reference identifying the specific occurrence (optional) */
|
|
305
|
+
instance?: string;
|
|
306
|
+
/** For validation errors, which field failed (extension) */
|
|
307
|
+
field?: string;
|
|
308
|
+
/** What constraint was violated (extension) */
|
|
309
|
+
constraint?: string;
|
|
310
|
+
/** For payment errors, which provider (extension) */
|
|
311
|
+
provider?: string;
|
|
312
|
+
/** Provider's error code (extension) */
|
|
313
|
+
provider_code?: string;
|
|
314
|
+
/** Allow additional extension fields */
|
|
315
|
+
[key: string]: unknown;
|
|
316
|
+
}
|
|
317
|
+
/** Error type constants matching server-side ErrorCodes */
|
|
318
|
+
declare const ErrorTypes: {
|
|
319
|
+
readonly VALIDATION_ERROR: "validation_error";
|
|
320
|
+
readonly BAD_REQUEST: "bad_request";
|
|
321
|
+
readonly NOT_AUTHENTICATED: "not_authenticated";
|
|
322
|
+
readonly INVALID_CREDENTIALS: "invalid_credentials";
|
|
323
|
+
readonly SESSION_EXPIRED: "session_expired";
|
|
324
|
+
readonly NOT_AUTHORIZED: "not_authorized";
|
|
325
|
+
readonly NOT_FOUND: "not_found";
|
|
326
|
+
readonly IDEMPOTENCY_CONFLICT: "idempotency_conflict";
|
|
327
|
+
readonly INTERNAL_ERROR: "internal_error";
|
|
328
|
+
readonly PAYMENT_DECLINED: "payment_declined";
|
|
329
|
+
readonly PAYMENT_FAILED: "payment_failed";
|
|
330
|
+
readonly VOUCHER_INVALID: "voucher_invalid";
|
|
331
|
+
readonly SEATS_EXCEEDED: "seats_exceeded";
|
|
332
|
+
readonly BOOKING_CONFLICT: "booking_conflict";
|
|
333
|
+
};
|
|
334
|
+
type ErrorType = (typeof ErrorTypes)[keyof typeof ErrorTypes];
|
|
335
|
+
/** Check if an error response is in RFC 7807 format */
|
|
336
|
+
declare function isProblemDetails(error: unknown): error is ProblemDetails;
|
|
337
|
+
|
|
338
|
+
declare class ErrorService {
|
|
339
|
+
/**
|
|
340
|
+
* Parse an HTTP error response into RFC 7807 ProblemDetails format.
|
|
341
|
+
* Handles both new RFC 7807 responses and legacy plain-text errors.
|
|
342
|
+
*/
|
|
343
|
+
parseError(error: HttpErrorResponse): ProblemDetails;
|
|
344
|
+
/**
|
|
345
|
+
* Get user-friendly message from a ProblemDetails error.
|
|
346
|
+
* The detail field should already be user-friendly.
|
|
347
|
+
*/
|
|
348
|
+
getUserFriendlyMessage(error: ProblemDetails): string;
|
|
349
|
+
private inferTypeFromStatus;
|
|
350
|
+
private getTitleForStatus;
|
|
351
|
+
private extractDetailFromError;
|
|
352
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ErrorService, never>;
|
|
353
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ErrorService>;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Phase 4.3 of the security review: companion to the server-side
|
|
358
|
+
* CsrfGuard middleware.
|
|
359
|
+
*
|
|
360
|
+
* On every state-changing request, read the `csrft` cookie that the
|
|
361
|
+
* backend set at login time (Phase 4.1), and copy its value into the
|
|
362
|
+
* `X-CSRF-Token` header. The double-submit pattern: an attacker on
|
|
363
|
+
* a different origin cannot read the cookie value across origins, so
|
|
364
|
+
* they can't forge a matching header.
|
|
365
|
+
*
|
|
366
|
+
* GETs / HEADs / OPTIONS pass through untouched. Requests that fire
|
|
367
|
+
* before the user has logged in (no cookie present) pass through
|
|
368
|
+
* unmodified — the server-side guard exempts the bootstrap endpoints
|
|
369
|
+
* (login / register / remember / verify) explicitly, so these still
|
|
370
|
+
* succeed.
|
|
371
|
+
*/
|
|
372
|
+
declare class CsrfInterceptor implements HttpInterceptor {
|
|
373
|
+
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>>;
|
|
374
|
+
private readCsrfCookie;
|
|
375
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<CsrfInterceptor, never>;
|
|
376
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<CsrfInterceptor>;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
declare function ColumnDataInfoFromJSON(obj: unknown): ColumnDataInfo;
|
|
380
|
+
|
|
381
|
+
export { AuthHttpAccess, ColumnDataInfoFromJSON, CrudHttpAccess, CsrfInterceptor, ErrorService, ErrorTypes, HONUWARE_API_BASE, HONUWARE_AUTH_ACCESS, HONUWARE_CRUD_ACCESS, HONUWARE_PHOTO_ACCESS, HonuwareAccessProxy, PhotoHttpAccess, PhotoUrlBuilder, isProblemDetails, provideHonuwareAccess };
|
|
382
|
+
export type { AddItemBody, AuthAccess, ColumnDataInfo, ComputedDateRule, CrudAccess, CrudFormAssist, DataResults, DataResultsWithCount, DatabaseSchema, ErrorType, FilterPair, FkDisplayResponse, FkOption, FkOptionsResponse, ForeignKeyInfo, HomePagePhotoInfo, HonuwareAccessConfig, LoginInfo, PhotoAccess, ProblemDetails, SetUserInfo, SourcePhotoInfo, TableBinding, TableSchema, UpdateItemBody, UpdateUserPasswordInfo, UserInfo };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { AuthAccess, UserInfo, ErrorService, ProblemDetails } from '@honuware/ui/access';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { InjectionToken, OnInit } from '@angular/core';
|
|
5
|
+
import { CanActivateFn, CanActivateChildFn, Router, ActivatedRoute } from '@angular/router';
|
|
6
|
+
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
|
|
7
|
+
import { FormGroup, FormBuilder } from '@angular/forms';
|
|
8
|
+
import { ToastService } from '@honuware/ui/foundation';
|
|
9
|
+
|
|
10
|
+
type AuthData = {
|
|
11
|
+
isAuth: false;
|
|
12
|
+
} | {
|
|
13
|
+
isAuth: true;
|
|
14
|
+
personId: number;
|
|
15
|
+
firstName: string;
|
|
16
|
+
lastName: string;
|
|
17
|
+
email: string;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
isAdmin: boolean;
|
|
20
|
+
roles: string[];
|
|
21
|
+
permissions: string[];
|
|
22
|
+
mustChangePassword: boolean;
|
|
23
|
+
};
|
|
24
|
+
declare const DEFAULT_NON_AUTH_DATA: AuthData;
|
|
25
|
+
declare function hasPermission(authData: AuthData, permission: string): boolean;
|
|
26
|
+
declare function hasManageProducts(authData: AuthData): boolean;
|
|
27
|
+
declare function hasStaffAccess(authData: AuthData): boolean;
|
|
28
|
+
|
|
29
|
+
declare class AuthService {
|
|
30
|
+
private authAccess;
|
|
31
|
+
private _authDataSubject;
|
|
32
|
+
get authData$(): Observable<AuthData>;
|
|
33
|
+
get authData(): AuthData;
|
|
34
|
+
constructor(authAccess: AuthAccess);
|
|
35
|
+
updateAuthData(userInfo: UserInfo): void;
|
|
36
|
+
setUserInfo(firstName: string, lastName: string, email: string): Observable<void>;
|
|
37
|
+
doSetUserInfo(firstName: string, lastName: string, email: string): void;
|
|
38
|
+
updateUserPassword(oldPassword: string, newPassword: string): Observable<void>;
|
|
39
|
+
doUpdateUserPassword(oldPassword: string, newPassword: string): void;
|
|
40
|
+
tryTokenLogin(): Observable<boolean>;
|
|
41
|
+
login(email: string, password: string, remember: boolean): Observable<void>;
|
|
42
|
+
logout(): Observable<void>;
|
|
43
|
+
register(firstName: string, lastName: string, email: string, password: string): Observable<void>;
|
|
44
|
+
verify(email: string, secret: string): Observable<void>;
|
|
45
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AuthService, never>;
|
|
46
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<AuthService>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface AuthRoutes {
|
|
50
|
+
/** Where the login page lives. */
|
|
51
|
+
loginPath: string;
|
|
52
|
+
/** Where the register page lives. */
|
|
53
|
+
registerPath: string;
|
|
54
|
+
/**
|
|
55
|
+
* Home path — used both after logout and as the "access denied" fallback
|
|
56
|
+
* for guard checks that reject the current user.
|
|
57
|
+
*/
|
|
58
|
+
postLogoutPath: string;
|
|
59
|
+
/** Forced-password-change page (users with must_change_password). */
|
|
60
|
+
mustChangePasswordPath: string;
|
|
61
|
+
/**
|
|
62
|
+
* Same-origin path prefixes a post-login returnUrl may target. Anything
|
|
63
|
+
* outside this list (or off-origin) is rejected to '/' by sanitizeReturnUrl.
|
|
64
|
+
*/
|
|
65
|
+
returnUrlAllowlist: ReadonlyArray<string>;
|
|
66
|
+
}
|
|
67
|
+
declare const DEFAULT_AUTH_ROUTES: AuthRoutes;
|
|
68
|
+
declare const AUTH_ROUTES: InjectionToken<AuthRoutes>;
|
|
69
|
+
|
|
70
|
+
declare const AdminGuard: CanActivateFn | CanActivateChildFn;
|
|
71
|
+
declare const AuthGuard: CanActivateFn | CanActivateChildFn;
|
|
72
|
+
declare const ManageProductsGuard: CanActivateFn | CanActivateChildFn;
|
|
73
|
+
declare const StaffGuard: CanActivateFn | CanActivateChildFn;
|
|
74
|
+
declare const NoAuthGuard: CanActivateFn | CanActivateChildFn;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Extended HttpErrorResponse that includes parsed ProblemDetails
|
|
78
|
+
*/
|
|
79
|
+
interface ParsedHttpErrorResponse extends HttpErrorResponse {
|
|
80
|
+
problemDetails: ProblemDetails;
|
|
81
|
+
}
|
|
82
|
+
declare class ErrorInterceptor implements HttpInterceptor {
|
|
83
|
+
private errorService;
|
|
84
|
+
private router;
|
|
85
|
+
private authRoutes;
|
|
86
|
+
constructor(errorService: ErrorService, router: Router, authRoutes: AuthRoutes);
|
|
87
|
+
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>>;
|
|
88
|
+
private isAuthEndpoint;
|
|
89
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ErrorInterceptor, never>;
|
|
90
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ErrorInterceptor>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declare class LoginComponent {
|
|
94
|
+
private fb;
|
|
95
|
+
private authService;
|
|
96
|
+
private router;
|
|
97
|
+
private route;
|
|
98
|
+
private toastService;
|
|
99
|
+
private errorService;
|
|
100
|
+
private authRoutes;
|
|
101
|
+
form: FormGroup;
|
|
102
|
+
hidePassword: boolean;
|
|
103
|
+
private returnUrl;
|
|
104
|
+
constructor(fb: FormBuilder, authService: AuthService, router: Router, route: ActivatedRoute, toastService: ToastService, errorService: ErrorService, authRoutes: AuthRoutes);
|
|
105
|
+
togglePasswordVisibility(): void;
|
|
106
|
+
onSignIn(): void;
|
|
107
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LoginComponent, never>;
|
|
108
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<LoginComponent, "hw-login", never, {}, {}, never, never, true, never>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
declare class RegisterComponent {
|
|
112
|
+
private fb;
|
|
113
|
+
private authService;
|
|
114
|
+
private router;
|
|
115
|
+
private toastService;
|
|
116
|
+
private errorService;
|
|
117
|
+
private authRoutes;
|
|
118
|
+
form: FormGroup;
|
|
119
|
+
hidePassword: boolean;
|
|
120
|
+
constructor(fb: FormBuilder, authService: AuthService, router: Router, toastService: ToastService, errorService: ErrorService, authRoutes: AuthRoutes);
|
|
121
|
+
togglePasswordVisibility(): void;
|
|
122
|
+
private passwordsMatchValidator;
|
|
123
|
+
onRegister(): void;
|
|
124
|
+
showPasswordMismatch(): boolean;
|
|
125
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RegisterComponent, never>;
|
|
126
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RegisterComponent, "hw-register", never, {}, {}, never, never, true, never>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Phase 3.3 of the security review.
|
|
131
|
+
*
|
|
132
|
+
* The verification email links at this SPA route — `/verify?email=…&secret=…` —
|
|
133
|
+
* rather than at the API. The component:
|
|
134
|
+
*
|
|
135
|
+
* 1. Reads `email` and `secret` from the query string.
|
|
136
|
+
* 2. Immediately calls `AuthService.verify(email, secret)` (POST /api/verify).
|
|
137
|
+
* 3. Right after firing the request, scrubs the URL via
|
|
138
|
+
* `history.replaceState({}, '', '/verify-success')` so the secret
|
|
139
|
+
* stops appearing in the URL bar / browser history. We do this
|
|
140
|
+
* synchronously, NOT inside the response callback, so the URL is
|
|
141
|
+
* sanitized whether the request succeeds, fails, or is delayed.
|
|
142
|
+
* 4. On success or failure, routes to `/login` with a toast. The two
|
|
143
|
+
* paths use different toasts but the toast text never echoes the
|
|
144
|
+
* server's error detail — failed verifications all collapse to one
|
|
145
|
+
* generic message to avoid distinguishing "wrong secret" from
|
|
146
|
+
* "expired" from "already verified".
|
|
147
|
+
*/
|
|
148
|
+
declare class VerifyComponent implements OnInit {
|
|
149
|
+
private route;
|
|
150
|
+
private router;
|
|
151
|
+
private authService;
|
|
152
|
+
private toastService;
|
|
153
|
+
private authRoutes;
|
|
154
|
+
constructor(route: ActivatedRoute, router: Router, authService: AuthService, toastService: ToastService, authRoutes: AuthRoutes);
|
|
155
|
+
ngOnInit(): void;
|
|
156
|
+
private scrubUrl;
|
|
157
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<VerifyComponent, never>;
|
|
158
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<VerifyComponent, "hw-verify", never, {}, {}, never, never, true, never>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
declare function tryTokenLoginInitializer(authService: AuthService): () => Promise<void>;
|
|
162
|
+
|
|
163
|
+
export { AUTH_ROUTES, AdminGuard, AuthGuard, AuthService, DEFAULT_AUTH_ROUTES, DEFAULT_NON_AUTH_DATA, ErrorInterceptor, LoginComponent, ManageProductsGuard, NoAuthGuard, RegisterComponent, StaffGuard, VerifyComponent, hasManageProducts, hasPermission, hasStaffAccess, tryTokenLoginInitializer };
|
|
164
|
+
export type { AuthData, AuthRoutes, ParsedHttpErrorResponse };
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { OnInit, OnChanges, EventEmitter, SimpleChanges, OnDestroy } from '@angular/core';
|
|
3
|
+
import { FormControl } from '@angular/forms';
|
|
4
|
+
import { ColumnDataInfo, ForeignKeyInfo, FkOption, CrudAccess } from '@honuware/ui/access';
|
|
5
|
+
|
|
6
|
+
declare class SimpleTextComponent implements OnInit, OnChanges {
|
|
7
|
+
dataInfo?: ColumnDataInfo;
|
|
8
|
+
value?: string;
|
|
9
|
+
readOnly: boolean;
|
|
10
|
+
valueChanged: EventEmitter<string>;
|
|
11
|
+
textInput: FormControl;
|
|
12
|
+
isLoading: boolean;
|
|
13
|
+
private skipValueChanges;
|
|
14
|
+
get displayLabel(): string;
|
|
15
|
+
ngOnInit(): void;
|
|
16
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
17
|
+
private getValidators;
|
|
18
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SimpleTextComponent, never>;
|
|
19
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SimpleTextComponent, "hw-simple-text", never, { "dataInfo": { "alias": "dataInfo"; "required": false; }; "value": { "alias": "value"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; }, { "valueChanged": "valueChanged"; }, never, never, true, never>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare class LongTextComponent implements OnInit, OnChanges {
|
|
23
|
+
dataInfo?: ColumnDataInfo;
|
|
24
|
+
value?: string;
|
|
25
|
+
readOnly: boolean;
|
|
26
|
+
valueChanged: EventEmitter<string>;
|
|
27
|
+
textInput: FormControl;
|
|
28
|
+
isLoading: boolean;
|
|
29
|
+
private skipValueChanges;
|
|
30
|
+
get displayLabel(): string;
|
|
31
|
+
ngOnInit(): void;
|
|
32
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
33
|
+
private getValidators;
|
|
34
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LongTextComponent, never>;
|
|
35
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<LongTextComponent, "hw-long-text", never, { "dataInfo": { "alias": "dataInfo"; "required": false; }; "value": { "alias": "value"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; }, { "valueChanged": "valueChanged"; }, never, never, true, never>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare class SimpleBoolComponent implements OnInit, OnChanges {
|
|
39
|
+
dataInfo?: ColumnDataInfo;
|
|
40
|
+
value?: string;
|
|
41
|
+
readOnly: boolean;
|
|
42
|
+
checkboxValueChange: EventEmitter<string>;
|
|
43
|
+
checkboxControl: FormControl;
|
|
44
|
+
isLoading: boolean;
|
|
45
|
+
private skipValueChanges;
|
|
46
|
+
private isTrueValue;
|
|
47
|
+
ngOnInit(): void;
|
|
48
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
49
|
+
private emitCheckboxValue;
|
|
50
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SimpleBoolComponent, never>;
|
|
51
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SimpleBoolComponent, "hw-simple-bool", never, { "dataInfo": { "alias": "dataInfo"; "required": false; }; "value": { "alias": "value"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; }, { "checkboxValueChange": "checkboxValueChange"; }, never, never, true, never>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
declare class SimpleEnumComponent implements OnInit, OnChanges {
|
|
55
|
+
dataInfo?: ColumnDataInfo;
|
|
56
|
+
value?: string;
|
|
57
|
+
readOnly: boolean;
|
|
58
|
+
enumValueChange: EventEmitter<string>;
|
|
59
|
+
selectControl: FormControl;
|
|
60
|
+
isLoading: boolean;
|
|
61
|
+
private skipValueChanges;
|
|
62
|
+
ngOnInit(): void;
|
|
63
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
64
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SimpleEnumComponent, never>;
|
|
65
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SimpleEnumComponent, "hw-simple-enum", never, { "dataInfo": { "alias": "dataInfo"; "required": false; }; "value": { "alias": "value"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; }, { "enumValueChange": "enumValueChange"; }, never, never, true, never>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
declare class SimpleDateComponent implements OnInit, OnChanges {
|
|
69
|
+
dataInfo?: ColumnDataInfo;
|
|
70
|
+
value?: string;
|
|
71
|
+
loading: boolean;
|
|
72
|
+
readOnly: boolean;
|
|
73
|
+
type: 'datetime' | 'date' | 'time';
|
|
74
|
+
timeIncrementMinutes: number;
|
|
75
|
+
valueChange: EventEmitter<string>;
|
|
76
|
+
dateControl: FormControl<any>;
|
|
77
|
+
private isMicrosecondInput;
|
|
78
|
+
private isBigIntColumn;
|
|
79
|
+
private parseInputValue;
|
|
80
|
+
ngOnInit(): void;
|
|
81
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
82
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SimpleDateComponent, never>;
|
|
83
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SimpleDateComponent, "hw-simple-date", never, { "dataInfo": { "alias": "dataInfo"; "required": false; }; "value": { "alias": "value"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "type": { "alias": "type"; "required": false; }; "timeIncrementMinutes": { "alias": "timeIncrementMinutes"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class FkPickerComponent implements OnInit, OnChanges, OnDestroy {
|
|
87
|
+
private serverAccess;
|
|
88
|
+
dataInfo?: ColumnDataInfo;
|
|
89
|
+
value?: string;
|
|
90
|
+
readOnly: boolean;
|
|
91
|
+
foreignKeyInfo?: ForeignKeyInfo;
|
|
92
|
+
preloadThreshold: number;
|
|
93
|
+
valueChanged: EventEmitter<string>;
|
|
94
|
+
searchControl: FormControl<string | null>;
|
|
95
|
+
filteredOptions: FkOption[];
|
|
96
|
+
isLoading: boolean;
|
|
97
|
+
resolvedDisplayText: string;
|
|
98
|
+
private selectedValue;
|
|
99
|
+
private skipValueChanges;
|
|
100
|
+
private searchSubject;
|
|
101
|
+
private subscriptions;
|
|
102
|
+
constructor(serverAccess: CrudAccess);
|
|
103
|
+
get displayLabel(): string;
|
|
104
|
+
ngOnInit(): void;
|
|
105
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
106
|
+
ngOnDestroy(): void;
|
|
107
|
+
displayFn: (option: FkOption | string) => string;
|
|
108
|
+
onOptionSelected(event: {
|
|
109
|
+
option: {
|
|
110
|
+
value: FkOption;
|
|
111
|
+
};
|
|
112
|
+
}): void;
|
|
113
|
+
private setupSearch;
|
|
114
|
+
private loadInitialOptions;
|
|
115
|
+
private updateSearchControlFromValue;
|
|
116
|
+
private resolveDisplayText;
|
|
117
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FkPickerComponent, never>;
|
|
118
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<FkPickerComponent, "hw-fk-picker", never, { "dataInfo": { "alias": "dataInfo"; "required": false; }; "value": { "alias": "value"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "foreignKeyInfo": { "alias": "foreignKeyInfo"; "required": false; }; "preloadThreshold": { "alias": "preloadThreshold"; "required": false; }; }, { "valueChanged": "valueChanged"; }, never, never, true, never>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
declare class CompositeControlComponent implements OnChanges {
|
|
122
|
+
dataInfo?: ColumnDataInfo;
|
|
123
|
+
value?: string;
|
|
124
|
+
readOnly: boolean;
|
|
125
|
+
foreignKeyInfo?: ForeignKeyInfo;
|
|
126
|
+
valueChanged: EventEmitter<string>;
|
|
127
|
+
isLoading: boolean;
|
|
128
|
+
activeComponent: 'text' | 'long-text' | 'bool' | 'date' | 'time' | 'enum' | 'fk' | null;
|
|
129
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
130
|
+
private determineActiveComponent;
|
|
131
|
+
onValueChanged(value: string): void;
|
|
132
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<CompositeControlComponent, never>;
|
|
133
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<CompositeControlComponent, "hw-composite-control", never, { "dataInfo": { "alias": "dataInfo"; "required": false; }; "value": { "alias": "value"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "foreignKeyInfo": { "alias": "foreignKeyInfo"; "required": false; }; }, { "valueChanged": "valueChanged"; }, never, never, true, never>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export { CompositeControlComponent, FkPickerComponent, LongTextComponent, SimpleBoolComponent, SimpleDateComponent, SimpleEnumComponent, SimpleTextComponent };
|