@pawells/nestjs-auth 1.0.0-dev.4c8c698
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/LICENSE +21 -0
- package/README.md +602 -0
- package/build/LICENSE +21 -0
- package/build/README.md +602 -0
- package/build/admin/client/client.d.ts +82 -0
- package/build/admin/client/client.d.ts.map +1 -0
- package/build/admin/client/client.js +157 -0
- package/build/admin/client/client.js.map +1 -0
- package/build/admin/client/errors/base-error.d.ts +58 -0
- package/build/admin/client/errors/base-error.d.ts.map +1 -0
- package/build/admin/client/errors/base-error.js +100 -0
- package/build/admin/client/errors/base-error.js.map +1 -0
- package/build/admin/client/errors/index.d.ts +2 -0
- package/build/admin/client/errors/index.d.ts.map +1 -0
- package/build/admin/client/errors/index.js +2 -0
- package/build/admin/client/errors/index.js.map +1 -0
- package/build/admin/client/index.d.ts +6 -0
- package/build/admin/client/index.d.ts.map +1 -0
- package/build/admin/client/index.js +11 -0
- package/build/admin/client/index.js.map +1 -0
- package/build/admin/client/services/authentication.service.d.ts +54 -0
- package/build/admin/client/services/authentication.service.d.ts.map +1 -0
- package/build/admin/client/services/authentication.service.js +99 -0
- package/build/admin/client/services/authentication.service.js.map +1 -0
- package/build/admin/client/services/base-service.d.ts +39 -0
- package/build/admin/client/services/base-service.d.ts.map +1 -0
- package/build/admin/client/services/base-service.js +107 -0
- package/build/admin/client/services/base-service.js.map +1 -0
- package/build/admin/client/services/client.service.d.ts +86 -0
- package/build/admin/client/services/client.service.d.ts.map +1 -0
- package/build/admin/client/services/client.service.js +193 -0
- package/build/admin/client/services/client.service.js.map +1 -0
- package/build/admin/client/services/event.service.d.ts +84 -0
- package/build/admin/client/services/event.service.d.ts.map +1 -0
- package/build/admin/client/services/event.service.js +155 -0
- package/build/admin/client/services/event.service.js.map +1 -0
- package/build/admin/client/services/federated-identity.service.d.ts +89 -0
- package/build/admin/client/services/federated-identity.service.d.ts.map +1 -0
- package/build/admin/client/services/federated-identity.service.js +120 -0
- package/build/admin/client/services/federated-identity.service.js.map +1 -0
- package/build/admin/client/services/group.service.d.ts +52 -0
- package/build/admin/client/services/group.service.d.ts.map +1 -0
- package/build/admin/client/services/group.service.js +105 -0
- package/build/admin/client/services/group.service.js.map +1 -0
- package/build/admin/client/services/identity-provider.service.d.ts +47 -0
- package/build/admin/client/services/identity-provider.service.d.ts.map +1 -0
- package/build/admin/client/services/identity-provider.service.js +86 -0
- package/build/admin/client/services/identity-provider.service.js.map +1 -0
- package/build/admin/client/services/index.d.ts +11 -0
- package/build/admin/client/services/index.d.ts.map +1 -0
- package/build/admin/client/services/index.js +11 -0
- package/build/admin/client/services/index.js.map +1 -0
- package/build/admin/client/services/realm.service.d.ts +41 -0
- package/build/admin/client/services/realm.service.d.ts.map +1 -0
- package/build/admin/client/services/realm.service.js +80 -0
- package/build/admin/client/services/realm.service.js.map +1 -0
- package/build/admin/client/services/role.service.d.ts +45 -0
- package/build/admin/client/services/role.service.d.ts.map +1 -0
- package/build/admin/client/services/role.service.js +92 -0
- package/build/admin/client/services/role.service.js.map +1 -0
- package/build/admin/client/services/user.service.d.ts +84 -0
- package/build/admin/client/services/user.service.d.ts.map +1 -0
- package/build/admin/client/services/user.service.js +216 -0
- package/build/admin/client/services/user.service.js.map +1 -0
- package/build/admin/client/types/config.types.d.ts +59 -0
- package/build/admin/client/types/config.types.d.ts.map +1 -0
- package/build/admin/client/types/config.types.js +13 -0
- package/build/admin/client/types/config.types.js.map +1 -0
- package/build/admin/client/types/event.types.d.ts +176 -0
- package/build/admin/client/types/event.types.d.ts.map +1 -0
- package/build/admin/client/types/event.types.js +2 -0
- package/build/admin/client/types/event.types.js.map +1 -0
- package/build/admin/client/types/index.d.ts +4 -0
- package/build/admin/client/types/index.d.ts.map +1 -0
- package/build/admin/client/types/index.js +4 -0
- package/build/admin/client/types/index.js.map +1 -0
- package/build/admin/client/types/keycloak.types.d.ts +169 -0
- package/build/admin/client/types/keycloak.types.d.ts.map +1 -0
- package/build/admin/client/types/keycloak.types.js +2 -0
- package/build/admin/client/types/keycloak.types.js.map +1 -0
- package/build/admin/client/utils/index.d.ts +2 -0
- package/build/admin/client/utils/index.d.ts.map +1 -0
- package/build/admin/client/utils/index.js +2 -0
- package/build/admin/client/utils/index.js.map +1 -0
- package/build/admin/client/utils/retry.d.ts +40 -0
- package/build/admin/client/utils/retry.d.ts.map +1 -0
- package/build/admin/client/utils/retry.js +72 -0
- package/build/admin/client/utils/retry.js.map +1 -0
- package/build/admin/config/keycloak.config.d.ts +33 -0
- package/build/admin/config/keycloak.config.d.ts.map +1 -0
- package/build/admin/config/keycloak.config.js +2 -0
- package/build/admin/config/keycloak.config.js.map +1 -0
- package/build/admin/config/keycloak.defaults.d.ts +11 -0
- package/build/admin/config/keycloak.defaults.d.ts.map +1 -0
- package/build/admin/config/keycloak.defaults.js +60 -0
- package/build/admin/config/keycloak.defaults.js.map +1 -0
- package/build/admin/health/keycloak.health.d.ts +13 -0
- package/build/admin/health/keycloak.health.d.ts.map +1 -0
- package/build/admin/health/keycloak.health.js +54 -0
- package/build/admin/health/keycloak.health.js.map +1 -0
- package/build/admin/index.d.ts +10 -0
- package/build/admin/index.d.ts.map +1 -0
- package/build/admin/index.js +9 -0
- package/build/admin/index.js.map +1 -0
- package/build/admin/keycloak-admin.interfaces.d.ts +45 -0
- package/build/admin/keycloak-admin.interfaces.d.ts.map +1 -0
- package/build/admin/keycloak-admin.interfaces.js +2 -0
- package/build/admin/keycloak-admin.interfaces.js.map +1 -0
- package/build/admin/keycloak-admin.module.d.ts +23 -0
- package/build/admin/keycloak-admin.module.d.ts.map +1 -0
- package/build/admin/keycloak-admin.module.js +101 -0
- package/build/admin/keycloak-admin.module.js.map +1 -0
- package/build/admin/keycloak.constants.d.ts +16 -0
- package/build/admin/keycloak.constants.d.ts.map +1 -0
- package/build/admin/keycloak.constants.js +16 -0
- package/build/admin/keycloak.constants.js.map +1 -0
- package/build/admin/permissions/index.d.ts +2 -0
- package/build/admin/permissions/index.d.ts.map +1 -0
- package/build/admin/permissions/index.js +2 -0
- package/build/admin/permissions/index.js.map +1 -0
- package/build/admin/permissions/keycloak-admin.permissions.d.ts +45 -0
- package/build/admin/permissions/keycloak-admin.permissions.d.ts.map +1 -0
- package/build/admin/permissions/keycloak-admin.permissions.js +68 -0
- package/build/admin/permissions/keycloak-admin.permissions.js.map +1 -0
- package/build/admin/services/keycloak-admin.service.d.ts +64 -0
- package/build/admin/services/keycloak-admin.service.d.ts.map +1 -0
- package/build/admin/services/keycloak-admin.service.js +152 -0
- package/build/admin/services/keycloak-admin.service.js.map +1 -0
- package/build/decorators/auth-decorators.d.ts +217 -0
- package/build/decorators/auth-decorators.d.ts.map +1 -0
- package/build/decorators/auth-decorators.js +251 -0
- package/build/decorators/auth-decorators.js.map +1 -0
- package/build/decorators/context-utils.d.ts +101 -0
- package/build/decorators/context-utils.d.ts.map +1 -0
- package/build/decorators/context-utils.js +178 -0
- package/build/decorators/context-utils.js.map +1 -0
- package/build/decorators/graphql-auth-decorators.d.ts +144 -0
- package/build/decorators/graphql-auth-decorators.d.ts.map +1 -0
- package/build/decorators/graphql-auth-decorators.js +152 -0
- package/build/decorators/graphql-auth-decorators.js.map +1 -0
- package/build/decorators/index.d.ts +5 -0
- package/build/decorators/index.d.ts.map +1 -0
- package/build/decorators/index.js +4 -0
- package/build/decorators/index.js.map +1 -0
- package/build/guards/index.d.ts +4 -0
- package/build/guards/index.d.ts.map +1 -0
- package/build/guards/index.js +4 -0
- package/build/guards/index.js.map +1 -0
- package/build/guards/jwt-auth.guard.d.ts +52 -0
- package/build/guards/jwt-auth.guard.d.ts.map +1 -0
- package/build/guards/jwt-auth.guard.js +97 -0
- package/build/guards/jwt-auth.guard.js.map +1 -0
- package/build/guards/permission.guard.d.ts +37 -0
- package/build/guards/permission.guard.d.ts.map +1 -0
- package/build/guards/permission.guard.js +73 -0
- package/build/guards/permission.guard.js.map +1 -0
- package/build/guards/role.guard.d.ts +33 -0
- package/build/guards/role.guard.d.ts.map +1 -0
- package/build/guards/role.guard.js +69 -0
- package/build/guards/role.guard.js.map +1 -0
- package/build/index.d.ts +92 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +98 -0
- package/build/index.js.map +1 -0
- package/build/keycloak/index.d.ts +7 -0
- package/build/keycloak/index.d.ts.map +1 -0
- package/build/keycloak/index.js +5 -0
- package/build/keycloak/index.js.map +1 -0
- package/build/keycloak/keycloak.constants.d.ts +2 -0
- package/build/keycloak/keycloak.constants.d.ts.map +1 -0
- package/build/keycloak/keycloak.constants.js +2 -0
- package/build/keycloak/keycloak.constants.js.map +1 -0
- package/build/keycloak/keycloak.interfaces.d.ts +12 -0
- package/build/keycloak/keycloak.interfaces.d.ts.map +1 -0
- package/build/keycloak/keycloak.interfaces.js +2 -0
- package/build/keycloak/keycloak.interfaces.js.map +1 -0
- package/build/keycloak/keycloak.module.d.ts +56 -0
- package/build/keycloak/keycloak.module.d.ts.map +1 -0
- package/build/keycloak/keycloak.module.js +104 -0
- package/build/keycloak/keycloak.module.js.map +1 -0
- package/build/keycloak/keycloak.types.d.ts +60 -0
- package/build/keycloak/keycloak.types.d.ts.map +1 -0
- package/build/keycloak/keycloak.types.js +2 -0
- package/build/keycloak/keycloak.types.js.map +1 -0
- package/build/keycloak/services/jwks-cache.service.d.ts +64 -0
- package/build/keycloak/services/jwks-cache.service.d.ts.map +1 -0
- package/build/keycloak/services/jwks-cache.service.js +176 -0
- package/build/keycloak/services/jwks-cache.service.js.map +1 -0
- package/build/keycloak/services/keycloak-token-validation.service.d.ts +88 -0
- package/build/keycloak/services/keycloak-token-validation.service.d.ts.map +1 -0
- package/build/keycloak/services/keycloak-token-validation.service.js +243 -0
- package/build/keycloak/services/keycloak-token-validation.service.js.map +1 -0
- package/build/package.json +72 -0
- package/package.json +93 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { AppLogger, getErrorMessage } from '@pawells/nestjs-shared/common';
|
|
2
|
+
import { withRetry } from '../utils/index.js';
|
|
3
|
+
import { KeycloakClientError, AuthenticationError, AuthorizationError, NotFoundError, ValidationError, TimeoutError, NetworkError, } from '../errors/index.js';
|
|
4
|
+
import { KeycloakAdminScopeError } from '../../permissions/keycloak-admin.permissions.js';
|
|
5
|
+
const HTTP_STATUS_UNAUTHORIZED = 401;
|
|
6
|
+
const HTTP_STATUS_FORBIDDEN = 403;
|
|
7
|
+
const HTTP_STATUS_NOT_FOUND = 404;
|
|
8
|
+
const HTTP_STATUS_BAD_REQUEST = 400;
|
|
9
|
+
const HTTP_STATUS_REQUEST_TIMEOUT = 408;
|
|
10
|
+
/**
|
|
11
|
+
* Base service class for Keycloak admin API client services.
|
|
12
|
+
*
|
|
13
|
+
* Provides shared functionality for all admin sub-services: error handling with classified
|
|
14
|
+
* exceptions, retry logic for transient failures, and scope-based access control.
|
|
15
|
+
* All Keycloak admin operations (user, role, client, group management, etc.) inherit from this class.
|
|
16
|
+
*
|
|
17
|
+
* Subclasses must call {@link requireScope} before API operations to enforce permission control.
|
|
18
|
+
*
|
|
19
|
+
* @abstract
|
|
20
|
+
*/
|
|
21
|
+
export class BaseService {
|
|
22
|
+
logger;
|
|
23
|
+
adminClient;
|
|
24
|
+
grantedScopes;
|
|
25
|
+
loggerConfig;
|
|
26
|
+
retryConfig;
|
|
27
|
+
constructor(adminClient, grantedScopes, loggerConfig, retryConfig) {
|
|
28
|
+
this.adminClient = adminClient;
|
|
29
|
+
this.grantedScopes = grantedScopes;
|
|
30
|
+
this.loggerConfig = loggerConfig;
|
|
31
|
+
this.retryConfig = retryConfig;
|
|
32
|
+
this.logger = new AppLogger(undefined, this.constructor.name);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Asserts that the given scope is granted. Throws {@link KeycloakAdminScopeError}
|
|
36
|
+
* synchronously if not, before any network request is made.
|
|
37
|
+
* All mutation operations ({@link KeycloakAdminScope} ending in `:write`) are
|
|
38
|
+
* audit-logged at INFO level when the check passes.
|
|
39
|
+
*/
|
|
40
|
+
requireScope(scope) {
|
|
41
|
+
if (!this.grantedScopes.has(scope)) {
|
|
42
|
+
this.logger.warn(`Keycloak admin scope blocked: '${scope}' not granted`);
|
|
43
|
+
throw new KeycloakAdminScopeError(scope);
|
|
44
|
+
}
|
|
45
|
+
if (scope.endsWith(':write')) {
|
|
46
|
+
this.logger.info(`Keycloak admin mutation: scope '${scope}' invoked`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Execute a function with retry logic
|
|
51
|
+
*/
|
|
52
|
+
async withRetry(fn, options) {
|
|
53
|
+
const config = {
|
|
54
|
+
...this.retryConfig,
|
|
55
|
+
...options,
|
|
56
|
+
...(this.loggerConfig && { logger: this.loggerConfig }),
|
|
57
|
+
};
|
|
58
|
+
const result = await withRetry(fn, config);
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Handle and transform errors from Keycloak admin client
|
|
63
|
+
*/
|
|
64
|
+
handleError(error) {
|
|
65
|
+
// Re-throw scope errors without wrapping
|
|
66
|
+
if (error instanceof KeycloakAdminScopeError) {
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
// If already our error type, re-throw
|
|
70
|
+
if (error instanceof KeycloakClientError) {
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
// Handle axios errors from admin client
|
|
74
|
+
if (error && typeof error === 'object' && 'response' in error) {
|
|
75
|
+
const axiosError = error;
|
|
76
|
+
const status = axiosError.response?.status;
|
|
77
|
+
const message = axiosError.message ?? 'Unknown error';
|
|
78
|
+
const data = axiosError.response?.data;
|
|
79
|
+
if (status === HTTP_STATUS_UNAUTHORIZED) {
|
|
80
|
+
throw new AuthenticationError(message, status, data);
|
|
81
|
+
}
|
|
82
|
+
if (status === HTTP_STATUS_FORBIDDEN) {
|
|
83
|
+
throw new AuthorizationError(message, status, data);
|
|
84
|
+
}
|
|
85
|
+
if (status === HTTP_STATUS_NOT_FOUND) {
|
|
86
|
+
throw new NotFoundError(message, data);
|
|
87
|
+
}
|
|
88
|
+
if (status === HTTP_STATUS_BAD_REQUEST) {
|
|
89
|
+
throw new ValidationError(message, data);
|
|
90
|
+
}
|
|
91
|
+
if (status === HTTP_STATUS_REQUEST_TIMEOUT) {
|
|
92
|
+
throw new TimeoutError(message);
|
|
93
|
+
}
|
|
94
|
+
if (axiosError.code === 'ECONNREFUSED' || axiosError.code === 'ETIMEDOUT') {
|
|
95
|
+
throw new NetworkError(message, error instanceof Error ? error : undefined);
|
|
96
|
+
}
|
|
97
|
+
// Generic error with status code
|
|
98
|
+
if (status) {
|
|
99
|
+
throw new KeycloakClientError(message, status, data);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Generic error
|
|
103
|
+
const message = getErrorMessage(error);
|
|
104
|
+
throw new KeycloakClientError(message, undefined, undefined, error instanceof Error ? error : undefined);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=base-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-service.js","sourceRoot":"","sources":["../../../../src/admin/client/services/base-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { ClientRepresentation, RoleRepresentation, ProtocolMapperRepresentation } from '../types/index.js';
|
|
2
|
+
import { BaseService } from './base-service.js';
|
|
3
|
+
/**
|
|
4
|
+
* Service for managing Keycloak OAuth/OIDC clients.
|
|
5
|
+
*
|
|
6
|
+
* Provides methods for CRUD operations on OAuth/OIDC clients, including client creation,
|
|
7
|
+
* configuration, secret rotation, client scope management, and protocol mapper setup.
|
|
8
|
+
* Requires `clients:read` and `clients:write` scopes depending on the operation.
|
|
9
|
+
*
|
|
10
|
+
* Part of {@link KeycloakAdminService.clients | KeycloakAdminService#clients}.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const clients = await keycloak.clients.list('my-realm');
|
|
15
|
+
* const client = await keycloak.clients.findByClientId('my-realm', 'my-app');
|
|
16
|
+
* await keycloak.clients.create('my-realm', {
|
|
17
|
+
* clientId: 'my-app',
|
|
18
|
+
* enabled: true,
|
|
19
|
+
* redirectUris: ['http://localhost:3000/callback'],
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare class ClientService extends BaseService {
|
|
24
|
+
/**
|
|
25
|
+
* List all clients in a realm
|
|
26
|
+
*/
|
|
27
|
+
list(realm: string): Promise<ClientRepresentation[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Get a client by ID (internal Keycloak ID, not clientId)
|
|
30
|
+
*/
|
|
31
|
+
get(realm: string, id: string): Promise<ClientRepresentation>;
|
|
32
|
+
/**
|
|
33
|
+
* Find a client by clientId (the public client identifier)
|
|
34
|
+
*/
|
|
35
|
+
findByClientId(realm: string, clientId: string): Promise<ClientRepresentation | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* Create a new client
|
|
38
|
+
*/
|
|
39
|
+
create(realm: string, client: ClientRepresentation): Promise<{
|
|
40
|
+
id: string;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* Update a client
|
|
44
|
+
*/
|
|
45
|
+
update(realm: string, id: string, client: ClientRepresentation): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Delete a client
|
|
48
|
+
*/
|
|
49
|
+
delete(realm: string, id: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Get client secret
|
|
52
|
+
*/
|
|
53
|
+
getSecret(realm: string, id: string): Promise<{
|
|
54
|
+
type?: string;
|
|
55
|
+
value?: string;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Create a protocol mapper for a client
|
|
59
|
+
*/
|
|
60
|
+
createProtocolMapper(realm: string, id: string, mapper: ProtocolMapperRepresentation): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* List protocol mappers for a client
|
|
63
|
+
*/
|
|
64
|
+
listProtocolMappers(realm: string, id: string): Promise<ProtocolMapperRepresentation[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Delete a protocol mapper
|
|
67
|
+
*/
|
|
68
|
+
deleteProtocolMapper(realm: string, id: string, mapperId: string): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Create a client role
|
|
71
|
+
*/
|
|
72
|
+
createRole(realm: string, id: string, role: RoleRepresentation): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* List roles for a client
|
|
75
|
+
*/
|
|
76
|
+
listRoles(realm: string, id: string): Promise<RoleRepresentation[]>;
|
|
77
|
+
/**
|
|
78
|
+
* Find a client role by name
|
|
79
|
+
*/
|
|
80
|
+
findRole(realm: string, id: string, roleName: string): Promise<RoleRepresentation>;
|
|
81
|
+
/**
|
|
82
|
+
* Delete a client role
|
|
83
|
+
*/
|
|
84
|
+
deleteRole(realm: string, id: string, roleName: string): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=client.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.service.d.ts","sourceRoot":"","sources":["../../../../src/admin/client/services/client.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EACpB,kBAAkB,EAClB,4BAA4B,EAC5B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC7C;;OAEG;IACU,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IASjE;;OAEG;IACU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAW1E;;OAEG;IACU,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;IAYvG;;OAEG;IACU,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAWzF;;OAEG;IACU,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3F;;OAEG;IACU,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7D;;OAEG;IACU,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAW7F;;OAEG;IACU,oBAAoB,CAChC,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,4BAA4B,GAClC,OAAO,CAAC,IAAI,CAAC;IAWhB;;OAEG;IACU,mBAAmB,CAC/B,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,GACR,OAAO,CAAC,4BAA4B,EAAE,CAAC;IAW1C;;OAEG;IACU,oBAAoB,CAChC,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAWhB;;OAEG;IACU,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3F;;OAEG;IACU,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAWhF;;OAEG;IACU,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAW/F;;OAEG;IACU,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUnF"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { BaseService } from './base-service.js';
|
|
2
|
+
/**
|
|
3
|
+
* Service for managing Keycloak OAuth/OIDC clients.
|
|
4
|
+
*
|
|
5
|
+
* Provides methods for CRUD operations on OAuth/OIDC clients, including client creation,
|
|
6
|
+
* configuration, secret rotation, client scope management, and protocol mapper setup.
|
|
7
|
+
* Requires `clients:read` and `clients:write` scopes depending on the operation.
|
|
8
|
+
*
|
|
9
|
+
* Part of {@link KeycloakAdminService.clients | KeycloakAdminService#clients}.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const clients = await keycloak.clients.list('my-realm');
|
|
14
|
+
* const client = await keycloak.clients.findByClientId('my-realm', 'my-app');
|
|
15
|
+
* await keycloak.clients.create('my-realm', {
|
|
16
|
+
* clientId: 'my-app',
|
|
17
|
+
* enabled: true,
|
|
18
|
+
* redirectUris: ['http://localhost:3000/callback'],
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class ClientService extends BaseService {
|
|
23
|
+
/**
|
|
24
|
+
* List all clients in a realm
|
|
25
|
+
*/
|
|
26
|
+
async list(realm) {
|
|
27
|
+
this.requireScope('clients:read');
|
|
28
|
+
try {
|
|
29
|
+
return (await this.withRetry(() => this.adminClient.clients.find({ realm })));
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return this.handleError(error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get a client by ID (internal Keycloak ID, not clientId)
|
|
37
|
+
*/
|
|
38
|
+
async get(realm, id) {
|
|
39
|
+
this.requireScope('clients:read');
|
|
40
|
+
try {
|
|
41
|
+
return (await this.withRetry(() => this.adminClient.clients.findOne({ realm, id })));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return this.handleError(error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Find a client by clientId (the public client identifier)
|
|
49
|
+
*/
|
|
50
|
+
async findByClientId(realm, clientId) {
|
|
51
|
+
this.requireScope('clients:read');
|
|
52
|
+
try {
|
|
53
|
+
const clients = (await this.withRetry(() => this.adminClient.clients.find({ realm, clientId })));
|
|
54
|
+
return clients[0];
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return this.handleError(error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create a new client
|
|
62
|
+
*/
|
|
63
|
+
async create(realm, client) {
|
|
64
|
+
this.requireScope('clients:write');
|
|
65
|
+
try {
|
|
66
|
+
return await this.withRetry(() => this.adminClient.clients.create({ ...client, realm }));
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return this.handleError(error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Update a client
|
|
74
|
+
*/
|
|
75
|
+
async update(realm, id, client) {
|
|
76
|
+
this.requireScope('clients:write');
|
|
77
|
+
try {
|
|
78
|
+
await this.withRetry(() => this.adminClient.clients.update({ realm, id }, client));
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
this.handleError(error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Delete a client
|
|
86
|
+
*/
|
|
87
|
+
async delete(realm, id) {
|
|
88
|
+
this.requireScope('clients:write');
|
|
89
|
+
try {
|
|
90
|
+
await this.withRetry(() => this.adminClient.clients.del({ realm, id }));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
this.handleError(error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get client secret
|
|
98
|
+
*/
|
|
99
|
+
async getSecret(realm, id) {
|
|
100
|
+
this.requireScope('clients:read');
|
|
101
|
+
try {
|
|
102
|
+
return await this.withRetry(() => this.adminClient.clients.getClientSecret({ realm, id }));
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return this.handleError(error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create a protocol mapper for a client
|
|
110
|
+
*/
|
|
111
|
+
async createProtocolMapper(realm, id, mapper) {
|
|
112
|
+
this.requireScope('clients:write');
|
|
113
|
+
try {
|
|
114
|
+
await this.withRetry(() => this.adminClient.clients.addProtocolMapper({ realm, id }, mapper));
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
this.handleError(error);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* List protocol mappers for a client
|
|
122
|
+
*/
|
|
123
|
+
async listProtocolMappers(realm, id) {
|
|
124
|
+
this.requireScope('clients:read');
|
|
125
|
+
try {
|
|
126
|
+
return (await this.withRetry(() => this.adminClient.clients.listProtocolMappers({ realm, id })));
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
return this.handleError(error);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Delete a protocol mapper
|
|
134
|
+
*/
|
|
135
|
+
async deleteProtocolMapper(realm, id, mapperId) {
|
|
136
|
+
this.requireScope('clients:write');
|
|
137
|
+
try {
|
|
138
|
+
await this.withRetry(() => this.adminClient.clients.delProtocolMapper({ realm, id, mapperId }));
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
this.handleError(error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Create a client role
|
|
146
|
+
*/
|
|
147
|
+
async createRole(realm, id, role) {
|
|
148
|
+
this.requireScope('clients:write');
|
|
149
|
+
try {
|
|
150
|
+
await this.withRetry(() => this.adminClient.clients.createRole({ realm, id }, role));
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
this.handleError(error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* List roles for a client
|
|
158
|
+
*/
|
|
159
|
+
async listRoles(realm, id) {
|
|
160
|
+
this.requireScope('clients:read');
|
|
161
|
+
try {
|
|
162
|
+
return (await this.withRetry(() => this.adminClient.clients.listRoles({ realm, id })));
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
return this.handleError(error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Find a client role by name
|
|
170
|
+
*/
|
|
171
|
+
async findRole(realm, id, roleName) {
|
|
172
|
+
this.requireScope('clients:read');
|
|
173
|
+
try {
|
|
174
|
+
return (await this.withRetry(() => this.adminClient.clients.findRole({ realm, id, roleName })));
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
return this.handleError(error);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Delete a client role
|
|
182
|
+
*/
|
|
183
|
+
async deleteRole(realm, id, roleName) {
|
|
184
|
+
this.requireScope('clients:write');
|
|
185
|
+
try {
|
|
186
|
+
await this.withRetry(() => this.adminClient.clients.delRole({ realm, id, roleName }));
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
this.handleError(error);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=client.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.service.js","sourceRoot":"","sources":["../../../../src/admin/client/services/client.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { AdminEventQuery, AccessEventQuery, KeycloakAdminEvent, KeycloakAccessEvent } from '../types/event.types.js';
|
|
2
|
+
import { BaseService } from './base-service.js';
|
|
3
|
+
/**
|
|
4
|
+
* Event Service
|
|
5
|
+
*
|
|
6
|
+
* Wraps Keycloak's event query endpoints for polling admin and access events.
|
|
7
|
+
* Intended for audit logging, monitoring, and event-driven integrations.
|
|
8
|
+
*
|
|
9
|
+
* Results are returned newest-first by default. Pagination is supported via `first` and `max` parameters.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Audit user deletions
|
|
14
|
+
* const events = await keycloakAdmin.events.getAdminEvents('master', {
|
|
15
|
+
* operationTypes: ['DELETE'],
|
|
16
|
+
* resourceTypes: ['USER'],
|
|
17
|
+
* max: 100
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Monitor failed logins
|
|
21
|
+
* const accessEvents = await keycloakAdmin.events.getAccessEvents('master', {
|
|
22
|
+
* type: ['LOGIN_ERROR'],
|
|
23
|
+
* max: 50
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare class EventService extends BaseService {
|
|
28
|
+
/**
|
|
29
|
+
* Get admin events for a realm
|
|
30
|
+
*
|
|
31
|
+
* Queries administrative events (user creation, role assignment, client updates, etc.).
|
|
32
|
+
* Results are newest-first. Use pagination via `first` and `max` to limit results.
|
|
33
|
+
*
|
|
34
|
+
* Note: Keycloak caps `max` at 100; larger values are silently truncated.
|
|
35
|
+
*
|
|
36
|
+
* @param realm - The realm name to query events for
|
|
37
|
+
* @param query - Optional filters and pagination parameters
|
|
38
|
+
* @returns Array of admin events (may be empty if no matches)
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const events = await this.events.getAdminEvents('master', {
|
|
43
|
+
* operationTypes: ['CREATE', 'UPDATE'],
|
|
44
|
+
* resourceTypes: ['USER', 'CLIENT'],
|
|
45
|
+
* dateFrom: new Date('2024-01-01'),
|
|
46
|
+
* dateTo: new Date(),
|
|
47
|
+
* max: 50
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
getAdminEvents(realm: string, query?: AdminEventQuery): Promise<KeycloakAdminEvent[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Get access events for a realm
|
|
54
|
+
*
|
|
55
|
+
* Queries authentication and authorization events (logins, logouts, permission checks, etc.).
|
|
56
|
+
* Results are newest-first. Use pagination via `first` and `max` to limit results.
|
|
57
|
+
*
|
|
58
|
+
* Note: Keycloak caps `max` at 100; larger values are silently truncated.
|
|
59
|
+
*
|
|
60
|
+
* @param realm - The realm name to query events for
|
|
61
|
+
* @param query - Optional filters and pagination parameters
|
|
62
|
+
* @returns Array of access events (may be empty if no matches)
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const events = await this.events.getAccessEvents('master', {
|
|
67
|
+
* type: ['LOGIN', 'LOGIN_ERROR'],
|
|
68
|
+
* client: 'my-client',
|
|
69
|
+
* dateFrom: new Date('2024-01-01'),
|
|
70
|
+
* max: 50
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
getAccessEvents(realm: string, query?: AccessEventQuery): Promise<KeycloakAccessEvent[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Build query parameters for admin events
|
|
77
|
+
*/
|
|
78
|
+
private buildAdminEventQuery;
|
|
79
|
+
/**
|
|
80
|
+
* Build query parameters for access events
|
|
81
|
+
*/
|
|
82
|
+
private buildAccessEventQuery;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=event.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.service.d.ts","sourceRoot":"","sources":["../../../../src/admin/client/services/event.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,YAAa,SAAQ,WAAW;IAC5C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACU,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAalG;;;;;;;;;;;;;;;;;;;;;OAqBG;IACU,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAarG;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAwC5B;;OAEG;IACH,OAAO,CAAC,qBAAqB;CAuC7B"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { BaseService } from './base-service.js';
|
|
2
|
+
/**
|
|
3
|
+
* Event Service
|
|
4
|
+
*
|
|
5
|
+
* Wraps Keycloak's event query endpoints for polling admin and access events.
|
|
6
|
+
* Intended for audit logging, monitoring, and event-driven integrations.
|
|
7
|
+
*
|
|
8
|
+
* Results are returned newest-first by default. Pagination is supported via `first` and `max` parameters.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Audit user deletions
|
|
13
|
+
* const events = await keycloakAdmin.events.getAdminEvents('master', {
|
|
14
|
+
* operationTypes: ['DELETE'],
|
|
15
|
+
* resourceTypes: ['USER'],
|
|
16
|
+
* max: 100
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Monitor failed logins
|
|
20
|
+
* const accessEvents = await keycloakAdmin.events.getAccessEvents('master', {
|
|
21
|
+
* type: ['LOGIN_ERROR'],
|
|
22
|
+
* max: 50
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export class EventService extends BaseService {
|
|
27
|
+
/**
|
|
28
|
+
* Get admin events for a realm
|
|
29
|
+
*
|
|
30
|
+
* Queries administrative events (user creation, role assignment, client updates, etc.).
|
|
31
|
+
* Results are newest-first. Use pagination via `first` and `max` to limit results.
|
|
32
|
+
*
|
|
33
|
+
* Note: Keycloak caps `max` at 100; larger values are silently truncated.
|
|
34
|
+
*
|
|
35
|
+
* @param realm - The realm name to query events for
|
|
36
|
+
* @param query - Optional filters and pagination parameters
|
|
37
|
+
* @returns Array of admin events (may be empty if no matches)
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const events = await this.events.getAdminEvents('master', {
|
|
42
|
+
* operationTypes: ['CREATE', 'UPDATE'],
|
|
43
|
+
* resourceTypes: ['USER', 'CLIENT'],
|
|
44
|
+
* dateFrom: new Date('2024-01-01'),
|
|
45
|
+
* dateTo: new Date(),
|
|
46
|
+
* max: 50
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
async getAdminEvents(realm, query) {
|
|
51
|
+
this.requireScope('events:read');
|
|
52
|
+
try {
|
|
53
|
+
const params = this.buildAdminEventQuery(query);
|
|
54
|
+
return (await this.withRetry(() => this.adminClient.realms.findAdminEvents({ realm, ...params })));
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return this.handleError(error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get access events for a realm
|
|
62
|
+
*
|
|
63
|
+
* Queries authentication and authorization events (logins, logouts, permission checks, etc.).
|
|
64
|
+
* Results are newest-first. Use pagination via `first` and `max` to limit results.
|
|
65
|
+
*
|
|
66
|
+
* Note: Keycloak caps `max` at 100; larger values are silently truncated.
|
|
67
|
+
*
|
|
68
|
+
* @param realm - The realm name to query events for
|
|
69
|
+
* @param query - Optional filters and pagination parameters
|
|
70
|
+
* @returns Array of access events (may be empty if no matches)
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const events = await this.events.getAccessEvents('master', {
|
|
75
|
+
* type: ['LOGIN', 'LOGIN_ERROR'],
|
|
76
|
+
* client: 'my-client',
|
|
77
|
+
* dateFrom: new Date('2024-01-01'),
|
|
78
|
+
* max: 50
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
async getAccessEvents(realm, query) {
|
|
83
|
+
this.requireScope('events:read');
|
|
84
|
+
try {
|
|
85
|
+
const params = this.buildAccessEventQuery(query);
|
|
86
|
+
return (await this.withRetry(() => this.adminClient.realms.findEvents({ realm, ...params })));
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return this.handleError(error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Build query parameters for admin events
|
|
94
|
+
*/
|
|
95
|
+
buildAdminEventQuery(query) {
|
|
96
|
+
const params = {};
|
|
97
|
+
if (!query) {
|
|
98
|
+
return params;
|
|
99
|
+
}
|
|
100
|
+
if (query.operationTypes && query.operationTypes.length > 0) {
|
|
101
|
+
params.operationTypes = query.operationTypes;
|
|
102
|
+
}
|
|
103
|
+
if (query.resourceTypes && query.resourceTypes.length > 0) {
|
|
104
|
+
params.resourceTypes = query.resourceTypes;
|
|
105
|
+
}
|
|
106
|
+
if (query.resourcePath) {
|
|
107
|
+
params.resourcePath = query.resourcePath;
|
|
108
|
+
}
|
|
109
|
+
if (query.dateFrom) {
|
|
110
|
+
params.dateFrom = query.dateFrom.toISOString();
|
|
111
|
+
}
|
|
112
|
+
if (query.dateTo) {
|
|
113
|
+
params.dateTo = query.dateTo.toISOString();
|
|
114
|
+
}
|
|
115
|
+
if (query.first !== undefined) {
|
|
116
|
+
params.first = query.first;
|
|
117
|
+
}
|
|
118
|
+
if (query.max !== undefined) {
|
|
119
|
+
params.max = query.max;
|
|
120
|
+
}
|
|
121
|
+
return params;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Build query parameters for access events
|
|
125
|
+
*/
|
|
126
|
+
buildAccessEventQuery(query) {
|
|
127
|
+
const params = {};
|
|
128
|
+
if (!query) {
|
|
129
|
+
return params;
|
|
130
|
+
}
|
|
131
|
+
if (query.type && query.type.length > 0) {
|
|
132
|
+
params.type = query.type;
|
|
133
|
+
}
|
|
134
|
+
if (query.client) {
|
|
135
|
+
params.client = query.client;
|
|
136
|
+
}
|
|
137
|
+
if (query.user) {
|
|
138
|
+
params.user = query.user;
|
|
139
|
+
}
|
|
140
|
+
if (query.dateFrom) {
|
|
141
|
+
params.dateFrom = query.dateFrom.toISOString();
|
|
142
|
+
}
|
|
143
|
+
if (query.dateTo) {
|
|
144
|
+
params.dateTo = query.dateTo.toISOString();
|
|
145
|
+
}
|
|
146
|
+
if (query.first !== undefined) {
|
|
147
|
+
params.first = query.first;
|
|
148
|
+
}
|
|
149
|
+
if (query.max !== undefined) {
|
|
150
|
+
params.max = query.max;
|
|
151
|
+
}
|
|
152
|
+
return params;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=event.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.service.js","sourceRoot":"","sources":["../../../../src/admin/client/services/event.service.ts"],"names":[],"mappings":"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"}
|