oip-common 0.3.2 → 0.4.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/index.d.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { OnDestroy, OnInit, DestroyRef, WritableSignal, OnChanges, SimpleChanges, Type, Provider, InjectionToken, EventEmitter, Renderer2, EnvironmentProviders } from '@angular/core';
3
- import { MessageService, ToastMessageOptions, MenuItem, ConfirmationService, FilterMetadata } from 'primeng/api';
2
+ import { OnDestroy, OnInit, DestroyRef, WritableSignal, OnChanges, SimpleChanges, Type, InjectionToken, Provider, EventEmitter, Renderer2, EnvironmentProviders } from '@angular/core';
3
+ import { MessageService, ToastMessageOptions, ConfirmationService, MenuItem, FilterMetadata } from 'primeng/api';
4
4
  import { ActivatedRoute, QueryParamsHandling, IsActiveMatchOptions, Params, Router, UrlTree } from '@angular/router';
5
5
  import { InterpolationParameters, Translation, TranslationObject, TranslateService } from '@ngx-translate/core';
6
6
  import * as rxjs from 'rxjs';
7
7
  import { Observable, BehaviorSubject, Subscription, Subject } from 'rxjs';
8
- import { LoginResponse, AuthOptions, OidcSecurityService, LogoutAuthOptions } from 'angular-auth-oidc-client';
9
8
  import { ContextMenu } from 'primeng/contextmenu';
10
9
  import { PaletteDesignToken, Preset } from '@primeuix/themes/types';
11
10
  import { PrimeNG } from 'primeng/config';
@@ -194,6 +193,10 @@ interface SecurityDto {
194
193
  type RefreshCustomParams = {
195
194
  [key: string]: string | number | boolean;
196
195
  };
196
+ type AuthSessionRefreshResult = {
197
+ isAuthenticated: boolean;
198
+ userData: any;
199
+ };
197
200
  type AuthCsrfToken = {
198
201
  token: string;
199
202
  headerName: string;
@@ -206,10 +209,10 @@ declare abstract class SecurityService {
206
209
  abstract isTokenExpired(): Observable<boolean>;
207
210
  abstract getCurrentUser(): any;
208
211
  abstract getCurrentUser$(): Observable<any>;
209
- abstract forceRefreshSession(customParams?: RefreshCustomParams, configId?: string): Observable<LoginResponse>;
212
+ abstract forceRefreshSession(customParams?: RefreshCustomParams, configId?: string): Observable<AuthSessionRefreshResult>;
210
213
  abstract getCsrfToken(): Observable<AuthCsrfToken | null>;
211
214
  abstract isAdmin(): boolean;
212
- abstract authorize(configId?: string, authOptions?: AuthOptions): void;
215
+ abstract authorize(): void;
213
216
  abstract payload: BehaviorSubject<any>;
214
217
  }
215
218
  declare class BffSecurityService implements OnDestroy, SecurityService {
@@ -225,7 +228,7 @@ declare class BffSecurityService implements OnDestroy, SecurityService {
225
228
  isTokenExpired(): Observable<boolean>;
226
229
  getCurrentUser(): any;
227
230
  getCurrentUser$(): Observable<any>;
228
- forceRefreshSession(): Observable<LoginResponse>;
231
+ forceRefreshSession(): Observable<AuthSessionRefreshResult>;
229
232
  getCsrfToken(): Observable<AuthCsrfToken | null>;
230
233
  isAdmin(): boolean;
231
234
  authorize(): void;
@@ -239,103 +242,6 @@ declare class BffSecurityService implements OnDestroy, SecurityService {
239
242
  static ɵfac: i0.ɵɵFactoryDeclaration<BffSecurityService, never>;
240
243
  static ɵprov: i0.ɵɵInjectableDeclaration<BffSecurityService>;
241
244
  }
242
- /**
243
- * SecurityService extends OidcSecurityService to manage authentication,
244
- * token handling, and user role access in an Angular application.
245
- *
246
- * It provides helper methods for checking authentication, managing tokens,
247
- * determining user roles, and performing logout and refresh operations.
248
- */
249
- declare class KeycloakSecurityService extends OidcSecurityService implements OnDestroy, SecurityService {
250
- private readonly refreshLockKeyPrefix;
251
- private readonly refreshResultKeyPrefix;
252
- private readonly refreshLockTtlMs;
253
- private readonly refreshWaitTimeoutMs;
254
- private readonly refreshTabId;
255
- private refreshSession$?;
256
- /**
257
- * Handles angular OIDC events.
258
- */
259
- private readonly publicEventsService;
260
- /**
261
- * Stores the latest login response from checkAuth().
262
- */
263
- loginResponse: BehaviorSubject<LoginResponse>;
264
- /**
265
- * Stores the decoded access token payload.
266
- */
267
- readonly payload: BehaviorSubject<any>;
268
- /**
269
- * Stores user-specific data from the login response.
270
- */
271
- private readonly currentUser;
272
- /**
273
- * Emits access token updates from initial auth check, manual refresh,
274
- * and library authentication events.
275
- */
276
- private accessToken;
277
- /**
278
- * Initializes service and subscribes to authentication events.
279
- * When a 'NewAuthenticationResult' event is received, the `auth` method is called.
280
- */
281
- constructor();
282
- getCurrentUser(): any;
283
- getCurrentUser$(): Observable<any>;
284
- /**
285
- * Returns the ID token for the sign-in.
286
- * @returns A string with the id token.
287
- */
288
- getAccessToken(configId?: string): Observable<string>;
289
- forceRefreshSession(customParams?: RefreshCustomParams, configId?: string): Observable<LoginResponse>;
290
- getCsrfToken(): Observable<AuthCsrfToken | null>;
291
- /**
292
- * Indicates whether the current user has the 'admin' role.
293
- *
294
- * @returns {boolean} True if the user is an admin, false otherwise.
295
- */
296
- isAdmin(): boolean;
297
- /**
298
- * Initiates authentication check and updates login response, user data,
299
- * and decoded token payload if authenticated.
300
- */
301
- auth(): void;
302
- /**
303
- * Performs logout and clears the local token payload.
304
- *
305
- * @param {string} [configId] Optional configuration ID for logout.
306
- * @param {LogoutAuthOptions} [logoutAuthOptions] Optional logout options.
307
- */
308
- logout(configId?: string, logoutAuthOptions?: LogoutAuthOptions): void;
309
- /**
310
- * Completes the BehaviorSubjects when the service is destroyed to avoid memory leaks.
311
- */
312
- ngOnDestroy(): void;
313
- /**
314
- * Checks whether the current access token is expired based on the 'exp' claim.
315
- *
316
- * @returns {Observable<boolean>} Observable that emits true if the token is expired.
317
- */
318
- isTokenExpired(): Observable<boolean>;
319
- private runSynchronizedRefresh;
320
- private runSynchronizedRefreshWithStorageLock;
321
- private refreshAsLockOwner;
322
- private syncAuthState;
323
- private applyLoginResponse;
324
- private isCurrentAccessTokenExpired;
325
- private tryAcquireRefreshLock;
326
- private releaseRefreshLock;
327
- private waitForRefreshResult;
328
- private tryResolveRefreshResult;
329
- private publishRefreshResult;
330
- private readRefreshLock;
331
- private readRefreshResult;
332
- private getRefreshLockKey;
333
- private getRefreshResultKey;
334
- private getWebLocks;
335
- private createRefreshTabId;
336
- static ɵfac: i0.ɵɵFactoryDeclaration<KeycloakSecurityService, never>;
337
- static ɵprov: i0.ɵɵInjectableDeclaration<KeycloakSecurityService>;
338
- }
339
245
 
340
246
  type QueryParamsType = Record<string | number, any>;
341
247
  type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;
@@ -648,7 +554,6 @@ declare class LogoService {
648
554
  }
649
555
 
650
556
  declare class AppTopbar {
651
- items: MenuItem[];
652
557
  securityService: SecurityService;
653
558
  topBarService: TopBarService;
654
559
  userService: UserService;
@@ -698,16 +603,6 @@ interface EditModuleInstanceDto {
698
603
  interface FolderModuleSettings {
699
604
  html?: string | null;
700
605
  }
701
- interface GetKeycloakClientSettingsResponse {
702
- authority?: string | null;
703
- clientId?: string | null;
704
- scope?: string | null;
705
- responseType?: string | null;
706
- useRefreshToken?: boolean;
707
- silentRenew?: boolean;
708
- logLevel?: number;
709
- secureRoutes?: string[] | null;
710
- }
711
606
  interface IframeModuleSettings {
712
607
  url?: string | null;
713
608
  }
@@ -1039,6 +934,86 @@ declare class AppModulesComponent implements OnInit {
1039
934
  static ɵcmp: i0.ɵɵComponentDeclaration<AppModulesComponent, "app-modules", never, {}, {}, never, never, true, never>;
1040
935
  }
1041
936
 
937
+ declare enum ServiceType {
938
+ Service = "Service",
939
+ Application = "Application"
940
+ }
941
+ interface ApplicationRegistryItemDto {
942
+ code?: string | null;
943
+ displayName?: string | null;
944
+ baseUrl?: string | null;
945
+ internalBaseUrl?: string | null;
946
+ icon?: string | null;
947
+ order?: number;
948
+ enabled?: boolean;
949
+ serviceType?: ServiceType;
950
+ isCurrent?: boolean;
951
+ }
952
+ interface GetApplicationRegistryItemByCodeParams {
953
+ code: string;
954
+ }
955
+ interface UpdateApplicationRegistryItemParams {
956
+ code: string;
957
+ }
958
+ interface DeleteApplicationRegistryItemParams {
959
+ code: string;
960
+ }
961
+
962
+ interface ApplicationEditModel {
963
+ code: string;
964
+ displayName: string;
965
+ baseUrl: string;
966
+ internalBaseUrl: string;
967
+ icon: string;
968
+ order: number;
969
+ enabled: boolean;
970
+ serviceType: NonNullable<ApplicationRegistryItemDto['serviceType']>;
971
+ }
972
+ interface ApplicationTableItem extends ApplicationRegistryItemDto {
973
+ _isEditing?: boolean;
974
+ _isNew?: boolean;
975
+ _editModel?: ApplicationEditModel;
976
+ }
977
+ declare class ApplicationsComponent implements OnInit {
978
+ protected readonly globalFilterFields: string[];
979
+ protected get serviceTypeOptions(): {
980
+ label: string;
981
+ value: NonNullable<ApplicationRegistryItemDto['serviceType']>;
982
+ }[];
983
+ protected applications: ApplicationTableItem[];
984
+ protected visibleApplications: ApplicationTableItem[];
985
+ protected globalFilter: string;
986
+ protected loading: boolean;
987
+ protected activeRowAction: boolean;
988
+ private readonly applicationsApi;
989
+ private readonly msgService;
990
+ private readonly l10nService;
991
+ private readonly titleService;
992
+ private readonly confirmationService;
993
+ private readonly translationsReady;
994
+ private draftApplication;
995
+ constructor();
996
+ ngOnInit(): Promise<void>;
997
+ protected refreshAction(): Promise<void>;
998
+ protected applyGlobalFilter(): void;
999
+ protected clearFilters(): void;
1000
+ protected beginCreateApplication(): void;
1001
+ protected editApplication(application: ApplicationTableItem): void;
1002
+ protected cancelEdit(application: ApplicationTableItem): void;
1003
+ protected saveApplication(application: ApplicationTableItem): Promise<void>;
1004
+ protected deleteApplication(application: ApplicationTableItem): Promise<void>;
1005
+ private createEditModel;
1006
+ private normalizeEditModel;
1007
+ protected serviceTypeLabel(serviceType: ApplicationRegistryItemDto['serviceType']): string;
1008
+ private cancelAllEdits;
1009
+ private syncVisibleApplications;
1010
+ private filterApplications;
1011
+ private getNextOrder;
1012
+ private t;
1013
+ static ɵfac: i0.ɵɵFactoryDeclaration<ApplicationsComponent, never>;
1014
+ static ɵcmp: i0.ɵɵComponentDeclaration<ApplicationsComponent, "app-applications", never, {}, {}, never, never, true, never>;
1015
+ }
1016
+
1042
1017
  declare type SurfacesType = {
1043
1018
  name?: string;
1044
1019
  palette?: PaletteDesignToken;
@@ -1344,6 +1319,25 @@ declare class UserNotificationsComponent {
1344
1319
  static ɵcmp: i0.ɵɵComponentDeclaration<UserNotificationsComponent, "app-user-notifications", never, {}, {}, never, never, true, never>;
1345
1320
  }
1346
1321
 
1322
+ declare class ApplicationRegistryService {
1323
+ private readonly applicationsApi;
1324
+ applications: ApplicationRegistryItemDto[];
1325
+ currentApplication: ApplicationRegistryItemDto | null;
1326
+ loadApplications(): Promise<void>;
1327
+ openApplication(application: ApplicationRegistryItemDto): void;
1328
+ static ɵfac: i0.ɵɵFactoryDeclaration<ApplicationRegistryService, never>;
1329
+ static ɵprov: i0.ɵɵInjectableDeclaration<ApplicationRegistryService>;
1330
+ }
1331
+
1332
+ declare class AppTopbarApplicationSwitcherComponent implements OnInit {
1333
+ protected applicationMenuItems: MenuItem[];
1334
+ protected readonly applicationRegistryService: ApplicationRegistryService;
1335
+ ngOnInit(): Promise<void>;
1336
+ private createApplicationMenuItem;
1337
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppTopbarApplicationSwitcherComponent, never>;
1338
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppTopbarApplicationSwitcherComponent, "app-topbar-application-switcher", never, {}, {}, never, never, true, never>;
1339
+ }
1340
+
1347
1341
  /**
1348
1342
  * A route guard that ensures the user is authenticated and has a valid access token.
1349
1343
  * If the access token is expired, it attempts to refresh the session.
@@ -1447,12 +1441,21 @@ declare class SecurityApi<SecurityDataType = unknown> extends HttpClient<Securit
1447
1441
  createAuthSession: (params?: RequestParams) => Promise<any>;
1448
1442
  deleteAuthSession: (params?: RequestParams) => Promise<any>;
1449
1443
  getAuthCsrfToken: (params?: RequestParams) => Promise<AuthCsrfTokenResponse>;
1450
- getKeycloakClientSettings: (params?: RequestParams) => Promise<GetKeycloakClientSettingsResponse>;
1451
1444
  getRealmRoles: (params?: RequestParams) => Promise<string[]>;
1452
1445
  static ɵfac: i0.ɵɵFactoryDeclaration<SecurityApi<any>, never>;
1453
1446
  static ɵprov: i0.ɵɵInjectableDeclaration<SecurityApi<any>>;
1454
1447
  }
1455
1448
 
1449
+ declare class ApplicationsApi<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
1450
+ getApplicationRegistryItems: (params?: RequestParams) => Promise<ApplicationRegistryItemDto[]>;
1451
+ getApplicationRegistryItemByCode: ({ code, ...query }: GetApplicationRegistryItemByCodeParams, params?: RequestParams) => Promise<any>;
1452
+ createApplicationRegistryItem: (data: ApplicationRegistryItemDto, params?: RequestParams) => Promise<any>;
1453
+ updateApplicationRegistryItem: ({ code, ...query }: UpdateApplicationRegistryItemParams, data: ApplicationRegistryItemDto, params?: RequestParams) => Promise<any>;
1454
+ deleteApplicationRegistryItem: ({ code, ...query }: DeleteApplicationRegistryItemParams, params?: RequestParams) => Promise<any>;
1455
+ static ɵfac: i0.ɵɵFactoryDeclaration<ApplicationsApi<any>, never>;
1456
+ static ɵprov: i0.ɵɵInjectableDeclaration<ApplicationsApi<any>>;
1457
+ }
1458
+
1456
1459
  interface UserSettingsDto {
1457
1460
  preset?: string | null;
1458
1461
  primary?: string | null;
@@ -1491,5 +1494,5 @@ declare class NotificationApi<SecurityDataType = unknown> extends HttpClient<Sec
1491
1494
  static ɵprov: i0.ɵɵInjectableDeclaration<NotificationApi<any>>;
1492
1495
  }
1493
1496
 
1494
- export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AuthGuardService, BaseModuleComponent, BffSecurityService, ConfigComponent, ContentType, DbMigrationComponent, DiscussionComponent, ErrorComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, KeycloakSecurityService, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationApi, NotificationService, ProfileComponent, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserService, convertToPrimeNgDateFormat, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, provideOip, replaceDefaults };
1497
+ export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AppTopbarApplicationSwitcherComponent, ApplicationRegistryService, ApplicationsApi, ApplicationsComponent, AuthGuardService, BaseModuleComponent, BffSecurityService, ConfigComponent, ContentType, DbMigrationComponent, DiscussionComponent, ErrorComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationApi, NotificationService, ProfileComponent, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserService, convertToPrimeNgDateFormat, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, provideOip, replaceDefaults };
1495
1498
  export type { AppConfig, AppThemePreset, AppThemePresetMergeMode, AuthCsrfToken, LanguageDto, MenuChangeEvent, NoSettingsDto, PutSecurityDto, RequestParams, SecurityDto, TopBarDto };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oip-common",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "A template for cross-platform web applications based on sakai-ng and primeNG",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -82,8 +82,28 @@ let config = {
82
82
  onCreateRequestParams: (rawType) => {},
83
83
  onCreateRoute: (routeData) => {},
84
84
  onCreateRouteName: (routeNameInfo, rawRouteInfo) => {
85
- if (routeNameInfo.usage.startsWith(rawRouteInfo.moduleName)) {
86
- const str = routeNameInfo.usage.substring(rawRouteInfo.moduleName.length);
85
+ const route = rawRouteInfo.route || rawRouteInfo.path || "<unknown route>";
86
+ const method = rawRouteInfo.method || rawRouteInfo.requestMethod || "<unknown method>";
87
+ const tags = Array.isArray(rawRouteInfo.tags) ? rawRouteInfo.tags.join(", ") : (rawRouteInfo.tags || "<none>");
88
+ const moduleName = rawRouteInfo.moduleName;
89
+
90
+ if (!moduleName) {
91
+ throw new Error(
92
+ `Invalid API route name for ${method.toUpperCase()} ${route}. Missing moduleName. Tags: ${tags}. ` +
93
+ "Add a controller tag/module name or provide explicit operationId.",
94
+ );
95
+ }
96
+
97
+ if (routeNameInfo.usage === moduleName) {
98
+ throw new Error(
99
+ `Invalid API route name for ${method.toUpperCase()} ${route}. Generated usage "${routeNameInfo.usage}" ` +
100
+ `equals moduleName "${moduleName}". Add an action segment in controller route, ` +
101
+ `e.g. [HttpGet("get-${moduleName}")], or provide explicit operationId.`,
102
+ );
103
+ }
104
+
105
+ if (routeNameInfo.usage.startsWith(moduleName)) {
106
+ const str = routeNameInfo.usage.substring(moduleName.length);
87
107
  routeNameInfo.usage = str[0].toLowerCase() + str.slice(1);
88
108
  routeNameInfo.original = routeNameInfo.usage;
89
109
  }