@friggframework/admin-scripts 2.0.0--canary.517.f04156f.0 → 2.0.0--canary.517.300ded3.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.js +2 -2
- package/package.json +6 -8
- package/src/application/__tests__/admin-frigg-commands.test.js +18 -18
- package/src/application/__tests__/script-runner.test.js +144 -14
- package/src/application/admin-frigg-commands.js +7 -7
- package/src/application/admin-script-base.js +2 -4
- package/src/application/script-runner.js +121 -127
- package/src/infrastructure/__tests__/admin-auth-middleware.test.js +32 -95
- package/src/infrastructure/__tests__/admin-script-router.test.js +24 -25
- package/src/infrastructure/admin-auth-middleware.js +5 -43
- package/src/infrastructure/admin-script-router.js +14 -16
- package/src/infrastructure/script-executor-handler.js +2 -2
- package/src/application/__tests__/dry-run-http-interceptor.test.js +0 -313
- package/src/application/__tests__/dry-run-repository-wrapper.test.js +0 -257
- package/src/application/dry-run-http-interceptor.js +0 -296
- package/src/application/dry-run-repository-wrapper.js +0 -261
package/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const { AdminFriggCommands, createAdminFriggCommands } = require('./src/applicat
|
|
|
12
12
|
const { ScriptRunner, createScriptRunner } = require('./src/application/script-runner');
|
|
13
13
|
|
|
14
14
|
// Infrastructure
|
|
15
|
-
const {
|
|
15
|
+
const { validateAdminApiKey } = require('./src/infrastructure/admin-auth-middleware');
|
|
16
16
|
const { router, app, handler: routerHandler } = require('./src/infrastructure/admin-script-router');
|
|
17
17
|
const { handler: executorHandler } = require('./src/infrastructure/script-executor-handler');
|
|
18
18
|
|
|
@@ -45,7 +45,7 @@ module.exports = {
|
|
|
45
45
|
createScriptRunner,
|
|
46
46
|
|
|
47
47
|
// Infrastructure layer
|
|
48
|
-
|
|
48
|
+
validateAdminApiKey,
|
|
49
49
|
router,
|
|
50
50
|
app,
|
|
51
51
|
routerHandler,
|
package/package.json
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/admin-scripts",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.517.
|
|
4
|
+
"version": "2.0.0--canary.517.300ded3.0",
|
|
5
5
|
"description": "Admin Script Runner for Frigg - Execute maintenance and operational scripts in hosted environments",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@aws-sdk/client-scheduler": "^3.588.0",
|
|
8
|
-
"@friggframework/core": "2.0.0--canary.517.
|
|
8
|
+
"@friggframework/core": "2.0.0--canary.517.300ded3.0",
|
|
9
9
|
"bcryptjs": "^2.4.3",
|
|
10
10
|
"express": "^4.18.2",
|
|
11
11
|
"lodash": "4.17.21",
|
|
12
|
-
"mongoose": "6.11.6",
|
|
13
12
|
"serverless-http": "^3.2.0",
|
|
14
13
|
"uuid": "^9.0.1"
|
|
15
14
|
},
|
|
16
15
|
"devDependencies": {
|
|
17
|
-
"@friggframework/eslint-config": "2.0.0--canary.517.
|
|
18
|
-
"@friggframework/prettier-config": "2.0.0--canary.517.
|
|
19
|
-
"@friggframework/test": "2.0.0--canary.517.
|
|
20
|
-
"chai": "^4.3.6",
|
|
16
|
+
"@friggframework/eslint-config": "2.0.0--canary.517.300ded3.0",
|
|
17
|
+
"@friggframework/prettier-config": "2.0.0--canary.517.300ded3.0",
|
|
18
|
+
"@friggframework/test": "2.0.0--canary.517.300ded3.0",
|
|
21
19
|
"eslint": "^8.22.0",
|
|
22
20
|
"jest": "^29.7.0",
|
|
23
21
|
"prettier": "^2.7.1",
|
|
@@ -49,5 +47,5 @@
|
|
|
49
47
|
"maintenance",
|
|
50
48
|
"operations"
|
|
51
49
|
],
|
|
52
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "300ded3ac35558075a081104b4b362b85cf0756f"
|
|
53
51
|
}
|
|
@@ -5,7 +5,7 @@ jest.mock('@friggframework/core/integrations/repositories/integration-repository
|
|
|
5
5
|
jest.mock('@friggframework/core/user/repositories/user-repository-factory');
|
|
6
6
|
jest.mock('@friggframework/core/modules/repositories/module-repository-factory');
|
|
7
7
|
jest.mock('@friggframework/core/credential/repositories/credential-repository-factory');
|
|
8
|
-
jest.mock('@friggframework/core/admin-scripts/repositories/
|
|
8
|
+
jest.mock('@friggframework/core/admin-scripts/repositories/admin-process-repository-factory');
|
|
9
9
|
jest.mock('@friggframework/core/queues');
|
|
10
10
|
|
|
11
11
|
describe('AdminFriggCommands', () => {
|
|
@@ -13,7 +13,7 @@ describe('AdminFriggCommands', () => {
|
|
|
13
13
|
let mockUserRepo;
|
|
14
14
|
let mockModuleRepo;
|
|
15
15
|
let mockCredentialRepo;
|
|
16
|
-
let
|
|
16
|
+
let mockAdminProcessRepo;
|
|
17
17
|
let mockQueuerUtil;
|
|
18
18
|
|
|
19
19
|
beforeEach(() => {
|
|
@@ -46,8 +46,8 @@ describe('AdminFriggCommands', () => {
|
|
|
46
46
|
updateCredential: jest.fn(),
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
mockAdminProcessRepo = {
|
|
50
|
+
appendProcessLog: jest.fn().mockResolvedValue(undefined),
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
mockQueuerUtil = {
|
|
@@ -60,14 +60,14 @@ describe('AdminFriggCommands', () => {
|
|
|
60
60
|
const { createUserRepository } = require('@friggframework/core/user/repositories/user-repository-factory');
|
|
61
61
|
const { createModuleRepository } = require('@friggframework/core/modules/repositories/module-repository-factory');
|
|
62
62
|
const { createCredentialRepository } = require('@friggframework/core/credential/repositories/credential-repository-factory');
|
|
63
|
-
const {
|
|
63
|
+
const { createAdminProcessRepository } = require('@friggframework/core/admin-scripts/repositories/admin-process-repository-factory');
|
|
64
64
|
const { QueuerUtil } = require('@friggframework/core/queues');
|
|
65
65
|
|
|
66
66
|
createIntegrationRepository.mockReturnValue(mockIntegrationRepo);
|
|
67
67
|
createUserRepository.mockReturnValue(mockUserRepo);
|
|
68
68
|
createModuleRepository.mockReturnValue(mockModuleRepo);
|
|
69
69
|
createCredentialRepository.mockReturnValue(mockCredentialRepo);
|
|
70
|
-
|
|
70
|
+
createAdminProcessRepository.mockReturnValue(mockAdminProcessRepo);
|
|
71
71
|
|
|
72
72
|
// Mock QueuerUtil methods
|
|
73
73
|
QueuerUtil.send = mockQueuerUtil.send;
|
|
@@ -158,16 +158,16 @@ describe('AdminFriggCommands', () => {
|
|
|
158
158
|
expect(repo).toBe(mockCredentialRepo);
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
it('creates
|
|
161
|
+
it('creates adminProcessRepository on first access', () => {
|
|
162
162
|
const commands = new AdminFriggCommands();
|
|
163
|
-
const {
|
|
163
|
+
const { createAdminProcessRepository } = require('@friggframework/core/admin-scripts/repositories/admin-process-repository-factory');
|
|
164
164
|
|
|
165
|
-
expect(
|
|
165
|
+
expect(createAdminProcessRepository).not.toHaveBeenCalled();
|
|
166
166
|
|
|
167
|
-
const repo = commands.
|
|
167
|
+
const repo = commands.adminProcessRepository;
|
|
168
168
|
|
|
169
|
-
expect(
|
|
170
|
-
expect(repo).toBe(
|
|
169
|
+
expect(createAdminProcessRepository).toHaveBeenCalledTimes(1);
|
|
170
|
+
expect(repo).toBe(mockAdminProcessRepo);
|
|
171
171
|
});
|
|
172
172
|
});
|
|
173
173
|
|
|
@@ -551,15 +551,15 @@ describe('AdminFriggCommands', () => {
|
|
|
551
551
|
it('log() persists if executionId set', async () => {
|
|
552
552
|
const commands = new AdminFriggCommands({ executionId: 'exec_123' });
|
|
553
553
|
// Force repository creation
|
|
554
|
-
commands.
|
|
554
|
+
commands.adminProcessRepository;
|
|
555
555
|
|
|
556
556
|
commands.log('warn', 'Warning message', { detail: 'xyz' });
|
|
557
557
|
|
|
558
558
|
// Give async operation a chance to execute
|
|
559
559
|
await new Promise(resolve => setImmediate(resolve));
|
|
560
560
|
|
|
561
|
-
expect(
|
|
562
|
-
const callArgs =
|
|
561
|
+
expect(mockAdminProcessRepo.appendProcessLog).toHaveBeenCalled();
|
|
562
|
+
const callArgs = mockAdminProcessRepo.appendProcessLog.mock.calls[0];
|
|
563
563
|
expect(callArgs[0]).toBe('exec_123');
|
|
564
564
|
expect(callArgs[1].level).toBe('warn');
|
|
565
565
|
expect(callArgs[1].message).toBe('Warning message');
|
|
@@ -572,14 +572,14 @@ describe('AdminFriggCommands', () => {
|
|
|
572
572
|
|
|
573
573
|
await new Promise(resolve => setImmediate(resolve));
|
|
574
574
|
|
|
575
|
-
expect(
|
|
575
|
+
expect(mockAdminProcessRepo.appendProcessLog).not.toHaveBeenCalled();
|
|
576
576
|
});
|
|
577
577
|
|
|
578
578
|
it('log() handles persistence failure gracefully', async () => {
|
|
579
579
|
const commands = new AdminFriggCommands({ executionId: 'exec_123' });
|
|
580
580
|
// Force repository creation
|
|
581
|
-
commands.
|
|
582
|
-
|
|
581
|
+
commands.adminProcessRepository;
|
|
582
|
+
mockAdminProcessRepo.appendProcessLog.mockRejectedValue(new Error('DB Error'));
|
|
583
583
|
|
|
584
584
|
// Should not throw
|
|
585
585
|
expect(() => commands.log('error', 'Test error')).not.toThrow();
|
|
@@ -36,9 +36,9 @@ describe('ScriptRunner', () => {
|
|
|
36
36
|
scriptFactory = new ScriptFactory([TestScript]);
|
|
37
37
|
|
|
38
38
|
mockCommands = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
createAdminProcess: jest.fn(),
|
|
40
|
+
updateAdminProcessState: jest.fn(),
|
|
41
|
+
completeAdminProcess: jest.fn(),
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
mockFrigg = {
|
|
@@ -49,11 +49,11 @@ describe('ScriptRunner', () => {
|
|
|
49
49
|
createAdminScriptCommands.mockReturnValue(mockCommands);
|
|
50
50
|
createAdminFriggCommands.mockReturnValue(mockFrigg);
|
|
51
51
|
|
|
52
|
-
mockCommands.
|
|
52
|
+
mockCommands.createAdminProcess.mockResolvedValue({
|
|
53
53
|
id: 'exec-123',
|
|
54
54
|
});
|
|
55
|
-
mockCommands.
|
|
56
|
-
mockCommands.
|
|
55
|
+
mockCommands.updateAdminProcessState.mockResolvedValue({});
|
|
56
|
+
mockCommands.completeAdminProcess.mockResolvedValue({ success: true });
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
afterEach(() => {
|
|
@@ -76,7 +76,7 @@ describe('ScriptRunner', () => {
|
|
|
76
76
|
expect(result.executionId).toBe('exec-123');
|
|
77
77
|
expect(result.metrics.durationMs).toBeGreaterThanOrEqual(0);
|
|
78
78
|
|
|
79
|
-
expect(mockCommands.
|
|
79
|
+
expect(mockCommands.createAdminProcess).toHaveBeenCalledWith({
|
|
80
80
|
scriptName: 'test-script',
|
|
81
81
|
scriptVersion: '1.0.0',
|
|
82
82
|
trigger: 'MANUAL',
|
|
@@ -85,15 +85,15 @@ describe('ScriptRunner', () => {
|
|
|
85
85
|
audit: { apiKeyName: 'test-key' },
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
expect(mockCommands.
|
|
88
|
+
expect(mockCommands.updateAdminProcessState).toHaveBeenCalledWith(
|
|
89
89
|
'exec-123',
|
|
90
90
|
'RUNNING'
|
|
91
91
|
);
|
|
92
92
|
|
|
93
|
-
expect(mockCommands.
|
|
93
|
+
expect(mockCommands.completeAdminProcess).toHaveBeenCalledWith(
|
|
94
94
|
'exec-123',
|
|
95
95
|
expect.objectContaining({
|
|
96
|
-
|
|
96
|
+
state: 'COMPLETED',
|
|
97
97
|
output: { success: true, params: { foo: 'bar' } },
|
|
98
98
|
metrics: expect.objectContaining({
|
|
99
99
|
durationMs: expect.any(Number),
|
|
@@ -128,10 +128,10 @@ describe('ScriptRunner', () => {
|
|
|
128
128
|
expect(result.scriptName).toBe('failing-script');
|
|
129
129
|
expect(result.error.message).toBe('Script failed');
|
|
130
130
|
|
|
131
|
-
expect(mockCommands.
|
|
131
|
+
expect(mockCommands.completeAdminProcess).toHaveBeenCalledWith(
|
|
132
132
|
'exec-123',
|
|
133
133
|
expect.objectContaining({
|
|
134
|
-
|
|
134
|
+
state: 'FAILED',
|
|
135
135
|
error: expect.objectContaining({
|
|
136
136
|
message: 'Script failed',
|
|
137
137
|
}),
|
|
@@ -178,14 +178,144 @@ describe('ScriptRunner', () => {
|
|
|
178
178
|
});
|
|
179
179
|
|
|
180
180
|
expect(result.executionId).toBe('existing-exec-456');
|
|
181
|
-
expect(mockCommands.
|
|
182
|
-
expect(mockCommands.
|
|
181
|
+
expect(mockCommands.createAdminProcess).not.toHaveBeenCalled();
|
|
182
|
+
expect(mockCommands.updateAdminProcessState).toHaveBeenCalledWith(
|
|
183
183
|
'existing-exec-456',
|
|
184
184
|
'RUNNING'
|
|
185
185
|
);
|
|
186
186
|
});
|
|
187
187
|
});
|
|
188
188
|
|
|
189
|
+
describe('dry-run mode', () => {
|
|
190
|
+
it('should return preview without executing script', async () => {
|
|
191
|
+
const runner = new ScriptRunner({ scriptFactory, commands: mockCommands });
|
|
192
|
+
|
|
193
|
+
const result = await runner.execute('test-script', { foo: 'bar' }, {
|
|
194
|
+
trigger: 'MANUAL',
|
|
195
|
+
dryRun: true,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
expect(result.dryRun).toBe(true);
|
|
199
|
+
expect(result.status).toBe('DRY_RUN_VALID');
|
|
200
|
+
expect(result.scriptName).toBe('test-script');
|
|
201
|
+
expect(result.preview.script.name).toBe('test-script');
|
|
202
|
+
expect(result.preview.script.version).toBe('1.0.0');
|
|
203
|
+
expect(result.preview.input).toEqual({ foo: 'bar' });
|
|
204
|
+
expect(result.message).toContain('validation passed');
|
|
205
|
+
|
|
206
|
+
// Should NOT create execution record or call commands
|
|
207
|
+
expect(mockCommands.createAdminProcess).not.toHaveBeenCalled();
|
|
208
|
+
expect(mockCommands.updateAdminProcessState).not.toHaveBeenCalled();
|
|
209
|
+
expect(mockCommands.completeAdminProcess).not.toHaveBeenCalled();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should validate required parameters in dry-run', async () => {
|
|
213
|
+
class SchemaScript extends AdminScriptBase {
|
|
214
|
+
static Definition = {
|
|
215
|
+
name: 'schema-script',
|
|
216
|
+
version: '1.0.0',
|
|
217
|
+
description: 'Script with schema',
|
|
218
|
+
inputSchema: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
required: ['requiredParam'],
|
|
221
|
+
properties: {
|
|
222
|
+
requiredParam: { type: 'string' },
|
|
223
|
+
optionalParam: { type: 'number' },
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
async execute() {
|
|
229
|
+
return {};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
scriptFactory.register(SchemaScript);
|
|
234
|
+
const runner = new ScriptRunner({ scriptFactory, commands: mockCommands });
|
|
235
|
+
|
|
236
|
+
// Missing required parameter
|
|
237
|
+
const result = await runner.execute('schema-script', {}, {
|
|
238
|
+
dryRun: true,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(result.status).toBe('DRY_RUN_INVALID');
|
|
242
|
+
expect(result.preview.validation.valid).toBe(false);
|
|
243
|
+
expect(result.preview.validation.errors).toContain('Missing required parameter: requiredParam');
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should validate parameter types in dry-run', async () => {
|
|
247
|
+
class TypedScript extends AdminScriptBase {
|
|
248
|
+
static Definition = {
|
|
249
|
+
name: 'typed-script',
|
|
250
|
+
version: '1.0.0',
|
|
251
|
+
description: 'Script with typed params',
|
|
252
|
+
inputSchema: {
|
|
253
|
+
type: 'object',
|
|
254
|
+
properties: {
|
|
255
|
+
count: { type: 'integer' },
|
|
256
|
+
name: { type: 'string' },
|
|
257
|
+
enabled: { type: 'boolean' },
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
async execute() {
|
|
263
|
+
return {};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
scriptFactory.register(TypedScript);
|
|
268
|
+
const runner = new ScriptRunner({ scriptFactory, commands: mockCommands });
|
|
269
|
+
|
|
270
|
+
const result = await runner.execute('typed-script', {
|
|
271
|
+
count: 'not-a-number',
|
|
272
|
+
name: 123,
|
|
273
|
+
enabled: 'true',
|
|
274
|
+
}, {
|
|
275
|
+
dryRun: true,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
expect(result.status).toBe('DRY_RUN_INVALID');
|
|
279
|
+
expect(result.preview.validation.errors).toHaveLength(3);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('should pass validation with correct parameters', async () => {
|
|
283
|
+
class ValidScript extends AdminScriptBase {
|
|
284
|
+
static Definition = {
|
|
285
|
+
name: 'valid-script',
|
|
286
|
+
version: '1.0.0',
|
|
287
|
+
description: 'Script for validation',
|
|
288
|
+
inputSchema: {
|
|
289
|
+
type: 'object',
|
|
290
|
+
required: ['name'],
|
|
291
|
+
properties: {
|
|
292
|
+
name: { type: 'string' },
|
|
293
|
+
count: { type: 'integer' },
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
async execute() {
|
|
299
|
+
return {};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
scriptFactory.register(ValidScript);
|
|
304
|
+
const runner = new ScriptRunner({ scriptFactory, commands: mockCommands });
|
|
305
|
+
|
|
306
|
+
const result = await runner.execute('valid-script', {
|
|
307
|
+
name: 'test',
|
|
308
|
+
count: 42,
|
|
309
|
+
}, {
|
|
310
|
+
dryRun: true,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
expect(result.status).toBe('DRY_RUN_VALID');
|
|
314
|
+
expect(result.preview.validation.valid).toBe(true);
|
|
315
|
+
expect(result.preview.validation.errors).toHaveLength(0);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
189
319
|
describe('createScriptRunner()', () => {
|
|
190
320
|
it('should create runner with default factory', () => {
|
|
191
321
|
const runner = createScriptRunner();
|
|
@@ -25,7 +25,7 @@ class AdminFriggCommands {
|
|
|
25
25
|
this._userRepository = null;
|
|
26
26
|
this._moduleRepository = null;
|
|
27
27
|
this._credentialRepository = null;
|
|
28
|
-
this.
|
|
28
|
+
this._adminProcessRepository = null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// ==================== LAZY-LOADED REPOSITORIES ====================
|
|
@@ -62,12 +62,12 @@ class AdminFriggCommands {
|
|
|
62
62
|
return this._credentialRepository;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
get
|
|
66
|
-
if (!this.
|
|
67
|
-
const {
|
|
68
|
-
this.
|
|
65
|
+
get adminProcessRepository() {
|
|
66
|
+
if (!this._adminProcessRepository) {
|
|
67
|
+
const { createAdminProcessRepository } = require('@friggframework/core/admin-scripts/repositories/admin-process-repository-factory');
|
|
68
|
+
this._adminProcessRepository = createAdminProcessRepository();
|
|
69
69
|
}
|
|
70
|
-
return this.
|
|
70
|
+
return this._adminProcessRepository;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// ==================== INTEGRATION QUERIES ====================
|
|
@@ -209,7 +209,7 @@ class AdminFriggCommands {
|
|
|
209
209
|
|
|
210
210
|
// Persist to execution record if we have an executionId
|
|
211
211
|
if (this.executionId) {
|
|
212
|
-
this.
|
|
212
|
+
this.adminProcessRepository.appendProcessLog(this.executionId, entry)
|
|
213
213
|
.catch(err => console.error('Failed to persist log:', err));
|
|
214
214
|
}
|
|
215
215
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const { createAdminApiKeyRepository } = require('@friggframework/core/admin-scripts/repositories/admin-api-key-repository-factory');
|
|
1
|
+
const { createAdminProcessRepository } = require('@friggframework/core/admin-scripts/repositories/admin-process-repository-factory');
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Admin Script Base Class
|
|
@@ -87,8 +86,7 @@ class AdminScriptBase {
|
|
|
87
86
|
this.integrationFactory = params.integrationFactory || null;
|
|
88
87
|
|
|
89
88
|
// OPTIONAL: Injected repositories (for testing or custom implementations)
|
|
90
|
-
this.
|
|
91
|
-
this.adminApiKeyRepository = params.adminApiKeyRepository || null;
|
|
89
|
+
this.adminProcessRepository = params.adminProcessRepository || null;
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
/**
|