keycloak-api-manager 6.0.0 → 6.0.2
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/Handlers/clientPoliciesHandler.js +4 -2
- package/Handlers/clientsHandler.js +1 -13
- package/Handlers/organizationsHandler.js +2 -1
- package/Handlers/realmsHandler.js +0 -1
- package/Handlers/userProfileHandler.js +2 -2
- package/OIDC_MIGRATION_PLAN.md +112 -42
- package/README.md +5 -3
- package/docs/api/configuration.md +39 -356
- package/docs/api-reference.md +7 -7
- package/docs/guides/PKCE-Login-Flow.md +13 -500
- package/index.js +131 -0
- package/package.json +1 -1
- package/test/helpers/config.js +15 -9
- package/test-output.log +0 -72
package/index.js
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* **************************************************************************************************
|
|
4
|
+
* Keycloak API Manager - Main Entry Point
|
|
5
|
+
*
|
|
6
|
+
* This module provides a centralized interface for managing Keycloak administrative resources via the REST Admin API.
|
|
7
|
+
* It exposes methods for client configuration, token handling, and wiring all resource handlers.
|
|
8
|
+
*
|
|
9
|
+
* Each handler in Handlers/ encapsulates logic for a specific Keycloak resource (users, roles, groups, etc.).
|
|
10
|
+
*
|
|
11
|
+
* NOTE: OIDC authentication functions are deprecated and have been moved to keycloak-express-middleware.
|
|
12
|
+
* **************************************************************************************************
|
|
13
|
+
*/
|
|
1
14
|
const KeycloakAdminClient = require('@keycloak/keycloak-admin-client').default;
|
|
2
15
|
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resource handler registry. Each key represents a Keycloak resource and maps to its handler module.
|
|
19
|
+
*/
|
|
3
20
|
const handlerRegistry = {
|
|
4
21
|
realms: require('./Handlers/realmsHandler'),
|
|
5
22
|
users: require('./Handlers/usersHandler'),
|
|
@@ -17,17 +34,33 @@ const handlerRegistry = {
|
|
|
17
34
|
serverInfo: require('./Handlers/serverInfoHandler')
|
|
18
35
|
};
|
|
19
36
|
|
|
37
|
+
|
|
38
|
+
// Keycloak Admin client instance
|
|
20
39
|
let kcAdminClient = null;
|
|
40
|
+
// Interval ID for automatic token refresh
|
|
21
41
|
let tokenRefreshInterval = null;
|
|
42
|
+
// Current runtime configuration
|
|
22
43
|
let runtimeConfig = null;
|
|
44
|
+
// Authentication payload used for token refresh
|
|
23
45
|
let authPayload = null;
|
|
24
46
|
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Ensures the client is configured before executing operations.
|
|
50
|
+
* Throws an error when configuration is missing.
|
|
51
|
+
*/
|
|
25
52
|
function assertConfigured() {
|
|
26
53
|
if (!kcAdminClient || !runtimeConfig) {
|
|
27
54
|
throw new Error('Keycloak Admin Client is not configured. Call configure() first.');
|
|
28
55
|
}
|
|
29
56
|
}
|
|
30
57
|
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Normalizes the baseUrl by removing a trailing slash, if present.
|
|
61
|
+
* @param {string} baseUrl
|
|
62
|
+
* @returns {string}
|
|
63
|
+
*/
|
|
31
64
|
function toBaseUrl(baseUrl) {
|
|
32
65
|
if (!baseUrl || typeof baseUrl !== 'string') {
|
|
33
66
|
throw new Error('Invalid baseUrl. It must be a non-empty string.');
|
|
@@ -35,6 +68,10 @@ function toBaseUrl(baseUrl) {
|
|
|
35
68
|
return baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
36
69
|
}
|
|
37
70
|
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Binds all resource handlers by injecting the configured Keycloak client and exporting the modules.
|
|
74
|
+
*/
|
|
38
75
|
function bindHandlers() {
|
|
39
76
|
Object.entries(handlerRegistry).forEach(([name, handler]) => {
|
|
40
77
|
handler.setKcAdminClient(kcAdminClient);
|
|
@@ -42,6 +79,10 @@ function bindHandlers() {
|
|
|
42
79
|
});
|
|
43
80
|
}
|
|
44
81
|
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Stops and resets the token refresh timer.
|
|
85
|
+
*/
|
|
45
86
|
function clearRefreshTimer() {
|
|
46
87
|
if (tokenRefreshInterval) {
|
|
47
88
|
clearInterval(tokenRefreshInterval);
|
|
@@ -49,6 +90,11 @@ function clearRefreshTimer() {
|
|
|
49
90
|
}
|
|
50
91
|
}
|
|
51
92
|
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Starts the automatic access token refresh timer.
|
|
96
|
+
* @param {number} intervalMs - interval in milliseconds
|
|
97
|
+
*/
|
|
52
98
|
function startRefreshTimer(intervalMs) {
|
|
53
99
|
clearRefreshTimer();
|
|
54
100
|
|
|
@@ -65,6 +111,25 @@ function startRefreshTimer(intervalMs) {
|
|
|
65
111
|
}
|
|
66
112
|
}
|
|
67
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Initializes and authenticates the Keycloak Admin Client. Must be called before using any handler.
|
|
116
|
+
* Supports password and client_credentials grant types.
|
|
117
|
+
* Starts automatic token refresh and propagates the configured client to all handlers.
|
|
118
|
+
*
|
|
119
|
+
* @param {Object} adminClientCredentials - Credentials and configuration object:
|
|
120
|
+
* - baseUrl {string} Keycloak server base URL
|
|
121
|
+
* - realmName {string} Realm name
|
|
122
|
+
* - clientId {string} Client ID
|
|
123
|
+
* - clientSecret {string} (optional) Secret for client_credentials
|
|
124
|
+
* - username {string} (optional) Admin username
|
|
125
|
+
* - password {string} (optional) Admin password
|
|
126
|
+
* - grantType {string} ("password" | "client_credentials")
|
|
127
|
+
* - tokenLifeSpan {number} (optional) Token refresh interval (seconds)
|
|
128
|
+
* - ... Other OAuth2 parameters
|
|
129
|
+
* @returns {Promise<void>} Promise resolved when configuration is complete
|
|
130
|
+
* @example
|
|
131
|
+
* await KeycloakManager.configure({ baseUrl, realmName, clientId, clientSecret, grantType: 'client_credentials' })
|
|
132
|
+
*/
|
|
68
133
|
exports.configure = async function configure(adminClientCredentials = {}) {
|
|
69
134
|
const {
|
|
70
135
|
baseUrl,
|
|
@@ -89,6 +154,8 @@ exports.configure = async function configure(adminClientCredentials = {}) {
|
|
|
89
154
|
realmName
|
|
90
155
|
});
|
|
91
156
|
|
|
157
|
+
// Guard against null/empty refresh token updates from upstream client internals.
|
|
158
|
+
// Without this, some refresh paths can keep a stale token value in memory.
|
|
92
159
|
const originalSetRefreshToken = kcAdminClient.setRefreshToken?.bind(kcAdminClient);
|
|
93
160
|
if (originalSetRefreshToken) {
|
|
94
161
|
kcAdminClient.setRefreshToken = (token) => {
|
|
@@ -100,6 +167,7 @@ exports.configure = async function configure(adminClientCredentials = {}) {
|
|
|
100
167
|
};
|
|
101
168
|
}
|
|
102
169
|
|
|
170
|
+
// Keep a canonical auth payload so the refresh timer can reuse the same grant context.
|
|
103
171
|
authPayload = {
|
|
104
172
|
clientId,
|
|
105
173
|
...(clientSecret ? { clientSecret } : {}),
|
|
@@ -107,6 +175,8 @@ exports.configure = async function configure(adminClientCredentials = {}) {
|
|
|
107
175
|
};
|
|
108
176
|
await kcAdminClient.auth(authPayload);
|
|
109
177
|
|
|
178
|
+
// Refresh midway through the configured lifespan to reduce expiration race conditions.
|
|
179
|
+
// Fallback to 30s when tokenLifeSpan is omitted/invalid.
|
|
110
180
|
const intervalMs = Number.isFinite(Number(tokenLifeSpan)) && Number(tokenLifeSpan) > 0
|
|
111
181
|
? (Number(tokenLifeSpan) * 1000) / 2
|
|
112
182
|
: 30000;
|
|
@@ -115,10 +185,40 @@ exports.configure = async function configure(adminClientCredentials = {}) {
|
|
|
115
185
|
bindHandlers();
|
|
116
186
|
};
|
|
117
187
|
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Updates Keycloak client runtime configuration without re-initializing the session or re-authenticating.
|
|
191
|
+
* Allows switching realm, baseUrl, or HTTP request options (requestConfig) at runtime.
|
|
192
|
+
*
|
|
193
|
+
* @param {Object} overrides - Configuration overrides object.
|
|
194
|
+
* @param {string} [overrides.realmName] - Changes the target realm for all subsequent calls.
|
|
195
|
+
* @param {string} [overrides.baseUrl] - Changes the Keycloak server base URL.
|
|
196
|
+
* @param {object} [overrides.requestConfig] - HTTP request option overrides (e.g., timeout, custom headers). These options are passed internally to the HTTP client used by keycloak-admin-client (typically Axios).
|
|
197
|
+
* @returns {void}
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* // Change only the realm
|
|
201
|
+
* KeycloakManager.setConfig({ realmName: 'my-app' });
|
|
202
|
+
*
|
|
203
|
+
* // Change realm and add custom request headers
|
|
204
|
+
* KeycloakManager.setConfig({
|
|
205
|
+
* realmName: 'my-realm',
|
|
206
|
+
* requestConfig: {
|
|
207
|
+
* timeout: 10000,
|
|
208
|
+
* headers: { 'X-Custom-Header': 'value' }
|
|
209
|
+
* }
|
|
210
|
+
* });
|
|
211
|
+
*
|
|
212
|
+
* // Change baseUrl (e.g., for different environments)
|
|
213
|
+
* KeycloakManager.setConfig({ baseUrl: 'https://keycloak-alt.example.com' });
|
|
214
|
+
*
|
|
215
|
+
* @note Does not perform login/token refresh. It only updates runtime context. The token remains valid if compatible with the new realm.
|
|
216
|
+
*/
|
|
118
217
|
exports.setConfig = function setConfig(configToOverride = {}) {
|
|
119
218
|
assertConfigured();
|
|
120
219
|
kcAdminClient.setConfig(configToOverride);
|
|
121
220
|
|
|
221
|
+
// Keep local runtimeConfig aligned with client overrides used by helper methods.
|
|
122
222
|
runtimeConfig = {
|
|
123
223
|
...runtimeConfig,
|
|
124
224
|
...(configToOverride.baseUrl ? { baseUrl: toBaseUrl(configToOverride.baseUrl) } : {}),
|
|
@@ -126,6 +226,16 @@ exports.setConfig = function setConfig(configToOverride = {}) {
|
|
|
126
226
|
};
|
|
127
227
|
};
|
|
128
228
|
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Returns the current access and refresh tokens.
|
|
232
|
+
* Useful for debugging or passing the token to other services.
|
|
233
|
+
* The token is automatically refreshed by the internal timer.
|
|
234
|
+
*
|
|
235
|
+
* @returns {{ accessToken: string, refreshToken: string }}
|
|
236
|
+
* @example
|
|
237
|
+
* const { accessToken } = KeycloakManager.getToken();
|
|
238
|
+
*/
|
|
129
239
|
exports.getToken = function getToken() {
|
|
130
240
|
assertConfigured();
|
|
131
241
|
return {
|
|
@@ -134,20 +244,40 @@ exports.getToken = function getToken() {
|
|
|
134
244
|
};
|
|
135
245
|
};
|
|
136
246
|
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Stops the automatic token refresh timer and releases resources.
|
|
250
|
+
* Call this before shutting down the application to avoid dangling processes.
|
|
251
|
+
*
|
|
252
|
+
* @returns {void}
|
|
253
|
+
* @example
|
|
254
|
+
* KeycloakManager.stop();
|
|
255
|
+
*/
|
|
137
256
|
exports.stop = function stop() {
|
|
138
257
|
clearRefreshTimer();
|
|
139
258
|
};
|
|
140
259
|
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Executes a direct request to the Keycloak OIDC token endpoint.
|
|
263
|
+
* Used internally for password, client_credentials, authorization_code (PKCE), and other grant types.
|
|
264
|
+
*
|
|
265
|
+
* @param {Object} credentials - OAuth2 parameters (grant_type, username, password, code, etc.)
|
|
266
|
+
* @returns {Promise<Object>} Token endpoint response (access_token, refresh_token, etc.)
|
|
267
|
+
* @throws {Error} If the request fails
|
|
268
|
+
*/
|
|
141
269
|
async function requestOidcToken(credentials = {}) {
|
|
142
270
|
assertConfigured();
|
|
143
271
|
|
|
144
272
|
const body = new URLSearchParams();
|
|
273
|
+
// Serialize only defined values to avoid sending "undefined"/"null" to Keycloak.
|
|
145
274
|
Object.entries(credentials).forEach(([key, value]) => {
|
|
146
275
|
if (value !== undefined && value !== null) {
|
|
147
276
|
body.append(key, String(value));
|
|
148
277
|
}
|
|
149
278
|
});
|
|
150
279
|
|
|
280
|
+
// Apply runtime client credentials as defaults unless explicitly overridden.
|
|
151
281
|
if (runtimeConfig.clientId && !body.has('client_id')) {
|
|
152
282
|
body.append('client_id', runtimeConfig.clientId);
|
|
153
283
|
}
|
|
@@ -167,6 +297,7 @@ async function requestOidcToken(credentials = {}) {
|
|
|
167
297
|
);
|
|
168
298
|
|
|
169
299
|
const responseText = await response.text();
|
|
300
|
+
// Keycloak usually returns JSON; keep empty-body responses safe.
|
|
170
301
|
const payload = responseText ? JSON.parse(responseText) : {};
|
|
171
302
|
|
|
172
303
|
if (!response.ok) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keycloak-api-manager",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.2",
|
|
4
4
|
"description": "Enhanced Node.js wrapper for Keycloak Admin REST API. Professional alternative to @keycloak/keycloak-admin-client with advanced features, bug fixes, automatic token refresh, Organizations API support, fine-grained permissions, and comprehensive resource management. Battle-tested with 113+ integration tests.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
package/test/helpers/config.js
CHANGED
|
@@ -79,8 +79,8 @@ function loadConfig() {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
82
|
+
* Initializes the Keycloak admin client.
|
|
83
|
+
* Waits until Keycloak is ready before connecting.
|
|
84
84
|
*/
|
|
85
85
|
async function initializeAdminClient() {
|
|
86
86
|
if (adminClient) {
|
|
@@ -90,6 +90,7 @@ async function initializeAdminClient() {
|
|
|
90
90
|
// Load configuration (after local.json has been created from Docker)
|
|
91
91
|
const config = loadConfig();
|
|
92
92
|
|
|
93
|
+
// Retry loop is intentionally generous to tolerate container cold-start time.
|
|
93
94
|
let retries = 30;
|
|
94
95
|
let lastError;
|
|
95
96
|
|
|
@@ -113,9 +114,11 @@ async function initializeAdminClient() {
|
|
|
113
114
|
lastError = err;
|
|
114
115
|
retries--;
|
|
115
116
|
if (retries > 0) {
|
|
117
|
+
// Keycloak may still be booting; wait and retry.
|
|
116
118
|
console.log(`Waiting for Keycloak... (${retries} retries left)`);
|
|
117
119
|
await delay(2000);
|
|
118
120
|
} else {
|
|
121
|
+
// Last attempt: print as much OAuth2 context as possible for diagnostics.
|
|
119
122
|
console.error('OAuth2 Error Details:', {
|
|
120
123
|
message: err.message,
|
|
121
124
|
response: err.response?.data,
|
|
@@ -130,21 +133,22 @@ async function initializeAdminClient() {
|
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
/**
|
|
133
|
-
*
|
|
136
|
+
* Creates the test realm.
|
|
134
137
|
*/
|
|
135
138
|
async function setupTestRealm() {
|
|
136
139
|
const client = await initializeAdminClient();
|
|
137
140
|
const config = loadConfig();
|
|
138
141
|
|
|
139
|
-
//
|
|
142
|
+
// Switch to the master realm to create the test realm
|
|
140
143
|
client.realmName = 'master';
|
|
141
144
|
|
|
142
145
|
try {
|
|
143
|
-
//
|
|
146
|
+
// Check if the realm already exists
|
|
144
147
|
const realms = await client.realms.find();
|
|
145
148
|
const realmExists = realms.some((r) => r.realm === config.realmName);
|
|
146
149
|
|
|
147
150
|
if (!realmExists) {
|
|
151
|
+
// Keep realm defaults explicit so tests behave consistently across environments.
|
|
148
152
|
await client.realms.create({
|
|
149
153
|
realm: config.realmName,
|
|
150
154
|
displayName: 'Test Realm',
|
|
@@ -159,6 +163,7 @@ async function setupTestRealm() {
|
|
|
159
163
|
console.log(`✓ Test realm '${config.realmName}' already exists`);
|
|
160
164
|
}
|
|
161
165
|
} catch (err) {
|
|
166
|
+
// 409 means the realm already exists, which is acceptable for idempotent setup.
|
|
162
167
|
if (err.response?.status === 409) {
|
|
163
168
|
console.log(`✓ Test realm '${config.realmName}' already exists`);
|
|
164
169
|
} else {
|
|
@@ -166,12 +171,12 @@ async function setupTestRealm() {
|
|
|
166
171
|
}
|
|
167
172
|
}
|
|
168
173
|
|
|
169
|
-
//
|
|
174
|
+
// Switch back to the test realm
|
|
170
175
|
client.realmName = config.realmName;
|
|
171
176
|
}
|
|
172
177
|
|
|
173
178
|
/**
|
|
174
|
-
*
|
|
179
|
+
* Cleans up the test realm.
|
|
175
180
|
*/
|
|
176
181
|
async function cleanupTestRealm() {
|
|
177
182
|
if (!adminClient) return;
|
|
@@ -183,6 +188,7 @@ async function cleanupTestRealm() {
|
|
|
183
188
|
await adminClient.realms.del({ realm: config.realmName });
|
|
184
189
|
console.log(`✓ Test realm '${config.realmName}' deleted`);
|
|
185
190
|
} catch (err) {
|
|
191
|
+
// Ignore not-found during cleanup to keep teardown idempotent.
|
|
186
192
|
if (err.response?.status !== 404) {
|
|
187
193
|
console.warn(`Warning: Failed to delete test realm: ${err.message}`);
|
|
188
194
|
}
|
|
@@ -190,7 +196,7 @@ async function cleanupTestRealm() {
|
|
|
190
196
|
}
|
|
191
197
|
|
|
192
198
|
/**
|
|
193
|
-
*
|
|
199
|
+
* Returns the configured and authenticated admin client.
|
|
194
200
|
*/
|
|
195
201
|
function getAdminClient() {
|
|
196
202
|
if (!adminClient) {
|
|
@@ -200,7 +206,7 @@ function getAdminClient() {
|
|
|
200
206
|
}
|
|
201
207
|
|
|
202
208
|
/**
|
|
203
|
-
*
|
|
209
|
+
* Resets the admin client (mainly for tests).
|
|
204
210
|
*/
|
|
205
211
|
function resetAdminClient() {
|
|
206
212
|
adminClient = null;
|
package/test-output.log
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> keycloak-api-manager@4.1.0 test
|
|
3
|
-
> npm --prefix test install && npm --prefix test test
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
up to date, audited 260 packages in 2s
|
|
7
|
-
|
|
8
|
-
48 packages are looking for funding
|
|
9
|
-
run `npm fund` for details
|
|
10
|
-
|
|
11
|
-
12 vulnerabilities (3 low, 3 moderate, 4 high, 2 critical)
|
|
12
|
-
|
|
13
|
-
To address all issues possible (including breaking changes), run:
|
|
14
|
-
npm audit fix --force
|
|
15
|
-
|
|
16
|
-
Some issues need review, and may require choosing
|
|
17
|
-
a different dependency.
|
|
18
|
-
|
|
19
|
-
Run `npm audit` for details.
|
|
20
|
-
|
|
21
|
-
> keycloak-api-manager-tests@1.0.0 test
|
|
22
|
-
> NODE_ENV=test NODE_PATH=./node_modules mocha --exit
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Exception during run: /Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/Handlers/userProfileHandler.js:79
|
|
26
|
-
body: JSON.strasync function(filter) {
|
|
27
|
-
^^^^^^^^
|
|
28
|
-
|
|
29
|
-
SyntaxError: Unexpected token 'function'
|
|
30
|
-
at wrapSafe (node:internal/modules/cjs/loader:1515:18)
|
|
31
|
-
at Module._compile (node:internal/modules/cjs/loader:1537:20)
|
|
32
|
-
at Object..js (node:internal/modules/cjs/loader:1708:10)
|
|
33
|
-
at Module.load (node:internal/modules/cjs/loader:1318:32)
|
|
34
|
-
at Function._load (node:internal/modules/cjs/loader:1128:12)
|
|
35
|
-
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
|
|
36
|
-
at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
|
|
37
|
-
at Module.require (node:internal/modules/cjs/loader:1340:12)
|
|
38
|
-
at require (node:internal/modules/helpers:138:16)
|
|
39
|
-
at Object.<anonymous> (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/index.js:15:24)
|
|
40
|
-
at Module._compile (node:internal/modules/cjs/loader:1565:14)
|
|
41
|
-
at Object..js (node:internal/modules/cjs/loader:1708:10)
|
|
42
|
-
at Module.load (node:internal/modules/cjs/loader:1318:32)
|
|
43
|
-
at Function._load (node:internal/modules/cjs/loader:1128:12)
|
|
44
|
-
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
|
|
45
|
-
at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
|
|
46
|
-
at Module.require (node:internal/modules/cjs/loader:1340:12)
|
|
47
|
-
at require (node:internal/modules/helpers:138:16)
|
|
48
|
-
at Object.<anonymous> (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/enableServerFeatures.js:47:25)
|
|
49
|
-
at Module._compile (node:internal/modules/cjs/loader:1565:14)
|
|
50
|
-
at Object..js (node:internal/modules/cjs/loader:1708:10)
|
|
51
|
-
at Module.load (node:internal/modules/cjs/loader:1318:32)
|
|
52
|
-
at Function._load (node:internal/modules/cjs/loader:1128:12)
|
|
53
|
-
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
|
|
54
|
-
at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
|
|
55
|
-
at Module.require (node:internal/modules/cjs/loader:1340:12)
|
|
56
|
-
at require (node:internal/modules/helpers:138:16)
|
|
57
|
-
at Object.<anonymous> (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/setup.js:29:30)
|
|
58
|
-
at Module._compile (node:internal/modules/cjs/loader:1565:14)
|
|
59
|
-
at Object..js (node:internal/modules/cjs/loader:1708:10)
|
|
60
|
-
at Module.load (node:internal/modules/cjs/loader:1318:32)
|
|
61
|
-
at Function._load (node:internal/modules/cjs/loader:1128:12)
|
|
62
|
-
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
|
|
63
|
-
at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
|
|
64
|
-
at cjsLoader (node:internal/modules/esm/translators:263:5)
|
|
65
|
-
at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:196:7)
|
|
66
|
-
at ModuleJob.run (node:internal/modules/esm/module_job:271:25)
|
|
67
|
-
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:547:26)
|
|
68
|
-
at async formattedImport (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/nodejs/esm-utils.js:9:14)
|
|
69
|
-
at async exports.requireOrImport (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/nodejs/esm-utils.js:42:28)
|
|
70
|
-
at async exports.loadFilesAsync (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/nodejs/esm-utils.js:100:20)
|
|
71
|
-
at async singleRun (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/cli/run-helpers.js:162:3)
|
|
72
|
-
at async exports.handler (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/cli/run.js:375:5)
|