@scenarist/core 0.2.0 → 0.3.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/dist/adapters/console-logger.d.ts +40 -0
- package/dist/adapters/console-logger.d.ts.map +1 -0
- package/dist/adapters/console-logger.js +193 -0
- package/dist/adapters/in-memory-state-manager.d.ts.map +1 -1
- package/dist/adapters/in-memory-state-manager.js +3 -0
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/noop-logger.d.ts +26 -0
- package/dist/adapters/noop-logger.d.ts.map +1 -0
- package/dist/adapters/noop-logger.js +26 -0
- package/dist/contracts/framework-adapter.d.ts +18 -0
- package/dist/contracts/framework-adapter.d.ts.map +1 -1
- package/dist/domain/config-builder.d.ts.map +1 -1
- package/dist/domain/config-builder.js +13 -0
- package/dist/domain/deep-equals.d.ts.map +1 -1
- package/dist/domain/deep-equals.js +2 -0
- package/dist/domain/index.d.ts +1 -0
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +1 -0
- package/dist/domain/log-events.d.ts +67 -0
- package/dist/domain/log-events.d.ts.map +1 -0
- package/dist/domain/log-events.js +70 -0
- package/dist/domain/path-extraction.js +1 -0
- package/dist/domain/regex-matching.d.ts.map +1 -1
- package/dist/domain/regex-matching.js +1 -0
- package/dist/domain/response-selector.d.ts +2 -1
- package/dist/domain/response-selector.d.ts.map +1 -1
- package/dist/domain/response-selector.js +93 -11
- package/dist/domain/scenario-manager.d.ts +4 -2
- package/dist/domain/scenario-manager.d.ts.map +1 -1
- package/dist/domain/scenario-manager.js +42 -24
- package/dist/domain/state-condition-evaluator.js +1 -0
- package/dist/domain/template-replacement.d.ts.map +1 -1
- package/dist/domain/template-replacement.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/ports/driven/logger.d.ts +119 -0
- package/dist/ports/driven/logger.d.ts.map +1 -0
- package/dist/ports/driven/logger.js +1 -0
- package/dist/ports/driven/response-selector.d.ts +3 -1
- package/dist/ports/driven/response-selector.d.ts.map +1 -1
- package/dist/ports/driven/response-selector.js +1 -0
- package/dist/ports/index.d.ts +1 -0
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/types/config.d.ts +29 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/errors.d.ts +49 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +26 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -1
- package/package.json +5 -5
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ScenaristError, ErrorCodes } from "../types/errors.js";
|
|
2
2
|
import { extractFromPath } from "./path-extraction.js";
|
|
3
3
|
import { applyTemplates } from "./template-replacement.js";
|
|
4
4
|
import { matchesRegex } from "./regex-matching.js";
|
|
5
5
|
import { createStateResponseResolver } from "./state-response-resolver.js";
|
|
6
6
|
import { deepEquals } from "./deep-equals.js";
|
|
7
|
+
import { noOpLogger } from "../adapters/index.js";
|
|
8
|
+
import { LogCategories, LogEvents } from "./log-events.js";
|
|
7
9
|
const SPECIFICITY_RANGES = {
|
|
8
10
|
MATCH_CRITERIA_BASE: 100,
|
|
9
11
|
SEQUENCE_FALLBACK: 1,
|
|
@@ -21,26 +23,41 @@ const SPECIFICITY_RANGES = {
|
|
|
21
23
|
* @param options.stateManager - Optional state manager for capture/injection (Phase 3)
|
|
22
24
|
*/
|
|
23
25
|
export const createResponseSelector = (options = {}) => {
|
|
24
|
-
const { sequenceTracker, stateManager } = options;
|
|
26
|
+
const { sequenceTracker, stateManager, logger = noOpLogger } = options;
|
|
25
27
|
return {
|
|
26
28
|
selectResponse(testId, scenarioId, context, mocks) {
|
|
29
|
+
const logContext = { testId, scenarioId };
|
|
30
|
+
// Log the number of candidate mocks
|
|
31
|
+
logger.debug(LogCategories.MATCHING, LogEvents.MOCK_CANDIDATES_FOUND, logContext, {
|
|
32
|
+
count: mocks.length,
|
|
33
|
+
});
|
|
27
34
|
let bestMatch = null;
|
|
35
|
+
// Track if we skipped any exhausted sequences (for better error messages)
|
|
36
|
+
let skippedExhaustedSequences = false;
|
|
28
37
|
// Find all matching mocks and score them by specificity
|
|
29
38
|
for (let mockIndex = 0; mockIndex < mocks.length; mockIndex++) {
|
|
30
|
-
//
|
|
39
|
+
// eslint-disable-next-line security/detect-object-injection -- Index bounded by loop (0 <= i < length)
|
|
31
40
|
const mockWithParams = mocks[mockIndex];
|
|
32
41
|
const mock = mockWithParams.mock;
|
|
33
42
|
// Skip exhausted sequences (repeat: 'none' that have been exhausted)
|
|
34
43
|
if (mock.sequence && sequenceTracker) {
|
|
35
44
|
const { exhausted } = sequenceTracker.getPosition(testId, scenarioId, mockIndex);
|
|
36
45
|
if (exhausted) {
|
|
46
|
+
skippedExhaustedSequences = true;
|
|
37
47
|
continue; // Skip to next mock, allowing fallback to be selected
|
|
38
48
|
}
|
|
39
49
|
}
|
|
40
50
|
// Check if this mock has match criteria
|
|
41
51
|
if (mock.match) {
|
|
42
52
|
// If match criteria exists, check if it matches the request
|
|
43
|
-
|
|
53
|
+
const matched = matchesCriteria(context, mock.match, testId, stateManager);
|
|
54
|
+
// Log the evaluation result
|
|
55
|
+
logger.debug(LogCategories.MATCHING, LogEvents.MOCK_MATCH_EVALUATED, logContext, {
|
|
56
|
+
mockIndex,
|
|
57
|
+
matched,
|
|
58
|
+
hasCriteria: true,
|
|
59
|
+
});
|
|
60
|
+
if (matched) {
|
|
44
61
|
// Match criteria always have higher priority than fallbacks
|
|
45
62
|
// Base specificity ensures even 1 field beats any fallback
|
|
46
63
|
const specificity = SPECIFICITY_RANGES.MATCH_CRITERIA_BASE +
|
|
@@ -55,9 +72,16 @@ export const createResponseSelector = (options = {}) => {
|
|
|
55
72
|
continue;
|
|
56
73
|
}
|
|
57
74
|
// No match criteria = fallback mock (always matches)
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
75
|
+
// Log fallback evaluation
|
|
76
|
+
logger.debug(LogCategories.MATCHING, LogEvents.MOCK_MATCH_EVALUATED, logContext, {
|
|
77
|
+
mockIndex,
|
|
78
|
+
matched: true,
|
|
79
|
+
hasCriteria: false,
|
|
80
|
+
});
|
|
81
|
+
// Dynamic response types (sequence, stateResponse) get higher priority than simple responses
|
|
82
|
+
// This ensures they are selected over simple fallback responses
|
|
83
|
+
// Both sequence and stateResponse get the same specificity (Issue #316 fix)
|
|
84
|
+
const fallbackSpecificity = mock.sequence || mock.stateResponse
|
|
61
85
|
? SPECIFICITY_RANGES.SEQUENCE_FALLBACK
|
|
62
86
|
: SPECIFICITY_RANGES.SIMPLE_FALLBACK;
|
|
63
87
|
if (!bestMatch || fallbackSpecificity >= bestMatch.specificity) {
|
|
@@ -73,14 +97,29 @@ export const createResponseSelector = (options = {}) => {
|
|
|
73
97
|
}
|
|
74
98
|
// Return the best matching mock
|
|
75
99
|
if (bestMatch) {
|
|
76
|
-
const { mockWithParams, mockIndex } = bestMatch;
|
|
100
|
+
const { mockWithParams, mockIndex, specificity } = bestMatch;
|
|
77
101
|
const mock = mockWithParams.mock;
|
|
102
|
+
// Log successful selection
|
|
103
|
+
logger.info(LogCategories.MATCHING, LogEvents.MOCK_SELECTED, logContext, {
|
|
104
|
+
mockIndex,
|
|
105
|
+
specificity,
|
|
106
|
+
});
|
|
78
107
|
// Select response (single, sequence, or stateResponse)
|
|
79
108
|
const response = selectResponseFromMock(testId, scenarioId, mockIndex, mock, sequenceTracker, stateManager);
|
|
80
109
|
if (!response) {
|
|
81
110
|
return {
|
|
82
111
|
success: false,
|
|
83
|
-
error: new
|
|
112
|
+
error: new ScenaristError(`Mock has neither response nor sequence field`, {
|
|
113
|
+
code: ErrorCodes.VALIDATION_ERROR,
|
|
114
|
+
context: {
|
|
115
|
+
testId,
|
|
116
|
+
scenarioId,
|
|
117
|
+
mockInfo: {
|
|
118
|
+
index: mockIndex,
|
|
119
|
+
},
|
|
120
|
+
hint: "Each mock must have a 'response', 'sequence', or 'stateResponse' field.",
|
|
121
|
+
},
|
|
122
|
+
}),
|
|
84
123
|
};
|
|
85
124
|
}
|
|
86
125
|
// Phase 3: Capture state from request if configured
|
|
@@ -105,10 +144,48 @@ export const createResponseSelector = (options = {}) => {
|
|
|
105
144
|
}
|
|
106
145
|
return { success: true, data: finalResponse };
|
|
107
146
|
}
|
|
108
|
-
// No mock matched
|
|
147
|
+
// No mock matched - determine specific error type
|
|
148
|
+
if (skippedExhaustedSequences) {
|
|
149
|
+
// All matching mocks were exhausted sequences
|
|
150
|
+
logger.warn(LogCategories.SEQUENCE, LogEvents.SEQUENCE_EXHAUSTED, logContext, {
|
|
151
|
+
url: context.url,
|
|
152
|
+
method: context.method,
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
error: new ScenaristError(`Sequence exhausted for ${context.method} ${context.url}. All responses have been consumed and repeat mode is 'none'.`, {
|
|
157
|
+
code: ErrorCodes.SEQUENCE_EXHAUSTED,
|
|
158
|
+
context: {
|
|
159
|
+
testId,
|
|
160
|
+
scenarioId,
|
|
161
|
+
requestInfo: {
|
|
162
|
+
method: context.method,
|
|
163
|
+
url: context.url,
|
|
164
|
+
},
|
|
165
|
+
hint: "Add a fallback mock to handle requests after sequence exhaustion, or use repeat: 'last' or 'cycle' instead of 'none'.",
|
|
166
|
+
},
|
|
167
|
+
}),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
logger.warn(LogCategories.MATCHING, LogEvents.MOCK_NO_MATCH, logContext, {
|
|
171
|
+
url: context.url,
|
|
172
|
+
method: context.method,
|
|
173
|
+
candidateCount: 0,
|
|
174
|
+
});
|
|
109
175
|
return {
|
|
110
176
|
success: false,
|
|
111
|
-
error: new
|
|
177
|
+
error: new ScenaristError(`No mock matched for ${context.method} ${context.url}`, {
|
|
178
|
+
code: ErrorCodes.NO_MOCK_FOUND,
|
|
179
|
+
context: {
|
|
180
|
+
testId,
|
|
181
|
+
scenarioId,
|
|
182
|
+
requestInfo: {
|
|
183
|
+
method: context.method,
|
|
184
|
+
url: context.url,
|
|
185
|
+
},
|
|
186
|
+
hint: "Add a fallback mock (without match criteria) to handle unmatched requests, or add a mock with matching criteria.",
|
|
187
|
+
},
|
|
188
|
+
}),
|
|
112
189
|
};
|
|
113
190
|
},
|
|
114
191
|
};
|
|
@@ -136,6 +213,7 @@ const selectResponseFromMock = (testId, scenarioId, mockIndex, mock, sequenceTra
|
|
|
136
213
|
// Get response at current position
|
|
137
214
|
// Note: Exhausted sequences are skipped during matching phase,
|
|
138
215
|
// so position should always be valid here
|
|
216
|
+
// eslint-disable-next-line security/detect-object-injection -- Position bounded by sequence tracker
|
|
139
217
|
const response = mock.sequence.responses[position];
|
|
140
218
|
// Advance position for next call
|
|
141
219
|
const repeatMode = mock.sequence.repeat || "last";
|
|
@@ -275,6 +353,7 @@ const matchesState = (stateCriteria, testId, stateManager) => {
|
|
|
275
353
|
return false;
|
|
276
354
|
}
|
|
277
355
|
// Deep equality check for values (handles primitives, null, objects)
|
|
356
|
+
// eslint-disable-next-line security/detect-object-injection -- Key from Object.entries iteration
|
|
278
357
|
if (!deepEquals(currentState[key], expectedValue)) {
|
|
279
358
|
return false;
|
|
280
359
|
}
|
|
@@ -295,6 +374,7 @@ const matchesBody = (requestBody, criteriaBody) => {
|
|
|
295
374
|
const body = requestBody;
|
|
296
375
|
// Check all required fields exist in request body with matching values
|
|
297
376
|
for (const [key, criteriaValue] of Object.entries(criteriaBody)) {
|
|
377
|
+
// eslint-disable-next-line security/detect-object-injection -- Key from Object.entries iteration
|
|
298
378
|
const requestValue = body[key];
|
|
299
379
|
// Convert to string for matching (type coercion like headers/query)
|
|
300
380
|
const stringValue = requestValue == null ? "" : String(requestValue);
|
|
@@ -377,6 +457,7 @@ const matchesHeaders = (requestHeaders, criteriaHeaders) => {
|
|
|
377
457
|
const normalizedRequest = createNormalizedHeaderMap(requestHeaders);
|
|
378
458
|
for (const [key, value] of Object.entries(criteriaHeaders)) {
|
|
379
459
|
const normalizedKey = normalizeHeaderName(key);
|
|
460
|
+
// eslint-disable-next-line security/detect-object-injection -- Key normalized from Object.entries iteration
|
|
380
461
|
const requestValue = normalizedRequest[normalizedKey];
|
|
381
462
|
if (!requestValue || !matchesValue(requestValue, value)) {
|
|
382
463
|
return false;
|
|
@@ -391,6 +472,7 @@ const matchesHeaders = (requestHeaders, criteriaHeaders) => {
|
|
|
391
472
|
const matchesQuery = (requestQuery, criteriaQuery) => {
|
|
392
473
|
// Check all required query params exist with exact matching values
|
|
393
474
|
for (const [key, value] of Object.entries(criteriaQuery)) {
|
|
475
|
+
// eslint-disable-next-line security/detect-object-injection -- Key from Object.entries iteration
|
|
394
476
|
const requestValue = requestQuery[key];
|
|
395
477
|
if (!requestValue || !matchesValue(requestValue, value)) {
|
|
396
478
|
return false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ScenarioManager, ScenarioRegistry, ScenarioStore, SequenceTracker, StateManager } from "../ports/index.js";
|
|
1
|
+
import type { ScenarioManager, ScenarioRegistry, ScenarioStore, SequenceTracker, StateManager, Logger } from "../ports/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Factory function to create a ScenarioManager implementation.
|
|
4
4
|
*
|
|
@@ -8,13 +8,15 @@ import type { ScenarioManager, ScenarioRegistry, ScenarioStore, SequenceTracker,
|
|
|
8
8
|
* - Any registry implementation (in-memory, Redis, files, remote)
|
|
9
9
|
* - Any store implementation (in-memory, Redis, database)
|
|
10
10
|
* - Any state manager implementation (in-memory, Redis, database)
|
|
11
|
+
* - Any logger implementation (console, file, remote)
|
|
11
12
|
* - Proper testing with mock dependencies
|
|
12
13
|
* - True hexagonal architecture
|
|
13
14
|
*/
|
|
14
|
-
export declare const createScenarioManager: ({ registry, store, stateManager, sequenceTracker, }: {
|
|
15
|
+
export declare const createScenarioManager: ({ registry, store, stateManager, sequenceTracker, logger, }: {
|
|
15
16
|
registry: ScenarioRegistry;
|
|
16
17
|
store: ScenarioStore;
|
|
17
18
|
stateManager?: StateManager;
|
|
18
19
|
sequenceTracker?: SequenceTracker;
|
|
20
|
+
logger?: Logger;
|
|
19
21
|
}) => ScenarioManager;
|
|
20
22
|
//# sourceMappingURL=scenario-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario-manager.d.ts","sourceRoot":"","sources":["../../src/domain/scenario-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,YAAY,
|
|
1
|
+
{"version":3,"file":"scenario-manager.d.ts","sourceRoot":"","sources":["../../src/domain/scenario-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,MAAM,EACP,MAAM,mBAAmB,CAAC;AAwC3B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,GAAI,6DAMnC;IACD,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,KAAG,eAwHH,CAAC"}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
|
+
import { noOpLogger } from "../adapters/index.js";
|
|
1
2
|
import { ScenaristScenarioSchema } from "../schemas/index.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
}
|
|
3
|
+
import { ScenaristError, ErrorCodes } from "../types/errors.js";
|
|
4
|
+
import { LogCategories, LogEvents } from "./log-events.js";
|
|
5
|
+
const createDuplicateScenarioError = (scenarioId) => {
|
|
6
|
+
return new ScenaristError(`Scenario '${scenarioId}' is already registered. Each scenario must have a unique ID.`, {
|
|
7
|
+
code: ErrorCodes.DUPLICATE_SCENARIO,
|
|
8
|
+
context: {
|
|
9
|
+
scenarioId,
|
|
10
|
+
hint: "Use a different scenario ID, or remove the existing scenario before registering a new one.",
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
const createScenarioValidationError = (scenarioId, validationErrors) => {
|
|
15
|
+
return new ScenaristError(`Invalid scenario definition for '${scenarioId}': ${validationErrors.join(", ")}`, {
|
|
16
|
+
code: ErrorCodes.VALIDATION_ERROR,
|
|
17
|
+
context: {
|
|
18
|
+
scenarioId,
|
|
19
|
+
hint: `Check your scenario definition. Validation errors: ${validationErrors.join("; ")}`,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
};
|
|
22
23
|
/**
|
|
23
24
|
* Factory function to create a ScenarioManager implementation.
|
|
24
25
|
*
|
|
@@ -28,10 +29,11 @@ class ScenarioValidationError extends Error {
|
|
|
28
29
|
* - Any registry implementation (in-memory, Redis, files, remote)
|
|
29
30
|
* - Any store implementation (in-memory, Redis, database)
|
|
30
31
|
* - Any state manager implementation (in-memory, Redis, database)
|
|
32
|
+
* - Any logger implementation (console, file, remote)
|
|
31
33
|
* - Proper testing with mock dependencies
|
|
32
34
|
* - True hexagonal architecture
|
|
33
35
|
*/
|
|
34
|
-
export const createScenarioManager = ({ registry, store, stateManager, sequenceTracker, }) => {
|
|
36
|
+
export const createScenarioManager = ({ registry, store, stateManager, sequenceTracker, logger = noOpLogger, }) => {
|
|
35
37
|
return {
|
|
36
38
|
registerScenario(definition) {
|
|
37
39
|
// Validate scenario definition at trust boundary
|
|
@@ -39,7 +41,7 @@ export const createScenarioManager = ({ registry, store, stateManager, sequenceT
|
|
|
39
41
|
if (!validationResult.success) {
|
|
40
42
|
const errorMessages = validationResult.error.issues.map((err) => `${err.path.join(".")}: ${err.message}`);
|
|
41
43
|
const scenarioId = definition?.id || "<unknown>";
|
|
42
|
-
throw
|
|
44
|
+
throw createScenarioValidationError(scenarioId, errorMessages);
|
|
43
45
|
}
|
|
44
46
|
const existing = registry.get(definition.id);
|
|
45
47
|
// Allow re-registering the exact same scenario object (idempotent)
|
|
@@ -48,16 +50,30 @@ export const createScenarioManager = ({ registry, store, stateManager, sequenceT
|
|
|
48
50
|
}
|
|
49
51
|
// Prevent registering a different scenario with the same ID
|
|
50
52
|
if (existing) {
|
|
51
|
-
throw
|
|
53
|
+
throw createDuplicateScenarioError(definition.id);
|
|
52
54
|
}
|
|
53
55
|
registry.register(definition);
|
|
56
|
+
logger.debug(LogCategories.SCENARIO, LogEvents.SCENARIO_REGISTERED, {}, {
|
|
57
|
+
scenarioId: definition.id,
|
|
58
|
+
mockCount: definition.mocks.length, // mocks is required by ScenaristScenarioSchema
|
|
59
|
+
});
|
|
54
60
|
},
|
|
55
61
|
switchScenario(testId, scenarioId) {
|
|
56
62
|
const definition = registry.get(scenarioId);
|
|
57
63
|
if (!definition) {
|
|
64
|
+
logger.error(LogCategories.SCENARIO, LogEvents.SCENARIO_NOT_FOUND, { testId }, {
|
|
65
|
+
requestedScenarioId: scenarioId,
|
|
66
|
+
});
|
|
58
67
|
return {
|
|
59
68
|
success: false,
|
|
60
|
-
error: new
|
|
69
|
+
error: new ScenaristError(`Scenario '${scenarioId}' not found. Did you forget to register it?`, {
|
|
70
|
+
code: ErrorCodes.SCENARIO_NOT_FOUND,
|
|
71
|
+
context: {
|
|
72
|
+
testId,
|
|
73
|
+
scenarioId,
|
|
74
|
+
hint: "Make sure to register the scenario before switching to it. Use manager.registerScenario(definition) first.",
|
|
75
|
+
},
|
|
76
|
+
}),
|
|
61
77
|
};
|
|
62
78
|
}
|
|
63
79
|
const activeScenario = {
|
|
@@ -72,6 +88,7 @@ export const createScenarioManager = ({ registry, store, stateManager, sequenceT
|
|
|
72
88
|
if (stateManager) {
|
|
73
89
|
stateManager.reset(testId);
|
|
74
90
|
}
|
|
91
|
+
logger.info(LogCategories.SCENARIO, LogEvents.SCENARIO_SWITCHED, { testId, scenarioId }, {});
|
|
75
92
|
return { success: true, data: undefined };
|
|
76
93
|
},
|
|
77
94
|
getActiveScenario(testId) {
|
|
@@ -82,6 +99,7 @@ export const createScenarioManager = ({ registry, store, stateManager, sequenceT
|
|
|
82
99
|
},
|
|
83
100
|
clearScenario(testId) {
|
|
84
101
|
store.delete(testId);
|
|
102
|
+
logger.debug(LogCategories.SCENARIO, LogEvents.SCENARIO_CLEARED, { testId }, {});
|
|
85
103
|
},
|
|
86
104
|
getScenarioById(id) {
|
|
87
105
|
return registry.get(id);
|
|
@@ -32,6 +32,7 @@ const stateMatchesCondition = (state, when) => {
|
|
|
32
32
|
if (!(key in state)) {
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
|
+
// eslint-disable-next-line security/detect-object-injection -- Key from Object.entries iteration
|
|
35
36
|
const actualValue = state[key];
|
|
36
37
|
if (!deepEquals(actualValue, expectedValue)) {
|
|
37
38
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-replacement.d.ts","sourceRoot":"","sources":["../../src/domain/template-replacement.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,OAAO,EACd,cAAc,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACpC,
|
|
1
|
+
{"version":3,"file":"template-replacement.d.ts","sourceRoot":"","sources":["../../src/domain/template-replacement.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,OAAO,EACd,cAAc,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACpC,OA+DF,CAAC"}
|
|
@@ -49,6 +49,7 @@ export const applyTemplates = (value, templateData) => {
|
|
|
49
49
|
if (typeof value === "object" && value !== null) {
|
|
50
50
|
const result = {};
|
|
51
51
|
for (const [key, val] of Object.entries(value)) {
|
|
52
|
+
// eslint-disable-next-line security/detect-object-injection -- Key from Object.entries iteration
|
|
52
53
|
result[key] = applyTemplates(val, normalizedData);
|
|
53
54
|
}
|
|
54
55
|
return result;
|
|
@@ -67,6 +68,7 @@ export const applyTemplates = (value, templateData) => {
|
|
|
67
68
|
*/
|
|
68
69
|
const resolveTemplatePath = (templateData, prefix, path) => {
|
|
69
70
|
// Get the root object (state or params)
|
|
71
|
+
// eslint-disable-next-line security/detect-object-injection -- Prefix validated as 'state' or 'params' by regex
|
|
70
72
|
const root = templateData[prefix];
|
|
71
73
|
// Guard: Prefix doesn't exist (e.g., no params provided)
|
|
72
74
|
if (root === undefined || typeof root !== "object" || root === null) {
|
|
@@ -86,6 +88,7 @@ const resolveTemplatePath = (templateData, prefix, path) => {
|
|
|
86
88
|
}
|
|
87
89
|
// Traverse object
|
|
88
90
|
const record = current;
|
|
91
|
+
// eslint-disable-next-line security/detect-object-injection -- Segment from split() iteration
|
|
89
92
|
current = record[segment];
|
|
90
93
|
// Guard: Return undefined if property doesn't exist
|
|
91
94
|
if (current === undefined) {
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,kBAAkB,CAAC;AAGtC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,sBAAsB,CAAC;AAGrC,mBAAmB,kBAAkB,CAAC;AAGtC,mBAAmB,sBAAsB,CAAC;AAG1C,cAAc,mBAAmB,CAAC;AAGlC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,kBAAkB,CAAC;AAGtC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/D,cAAc,oBAAoB,CAAC;AAGnC,cAAc,sBAAsB,CAAC;AAGrC,mBAAmB,kBAAkB,CAAC;AAGtC,mBAAmB,sBAAsB,CAAC;AAG1C,cAAc,mBAAmB,CAAC;AAGlC,cAAc,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log levels ordered by verbosity (ascending).
|
|
3
|
+
* Each level includes all less verbose levels.
|
|
4
|
+
*
|
|
5
|
+
* - silent: No output (production default)
|
|
6
|
+
* - error: Critical failures preventing operation
|
|
7
|
+
* - warn: Potential issues that may cause problems
|
|
8
|
+
* - info: Operation flow and key events
|
|
9
|
+
* - debug: Detailed decision logic
|
|
10
|
+
* - trace: Request/response bodies, verbose details
|
|
11
|
+
*/
|
|
12
|
+
export type LogLevel = "silent" | "error" | "warn" | "info" | "debug" | "trace";
|
|
13
|
+
/**
|
|
14
|
+
* Log categories for filtering specific areas of concern.
|
|
15
|
+
* Users can enable/disable categories independently.
|
|
16
|
+
*/
|
|
17
|
+
export type LogCategory = "lifecycle" | "scenario" | "matching" | "sequence" | "state" | "template" | "request";
|
|
18
|
+
/**
|
|
19
|
+
* Base context included in all log events.
|
|
20
|
+
* Enables filtering and correlation by test ID.
|
|
21
|
+
*/
|
|
22
|
+
export type LogContext = {
|
|
23
|
+
readonly testId?: string;
|
|
24
|
+
readonly scenarioId?: string;
|
|
25
|
+
readonly requestUrl?: string;
|
|
26
|
+
readonly requestMethod?: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Structured log entry for capture and serialization.
|
|
30
|
+
*/
|
|
31
|
+
export type LogEntry = {
|
|
32
|
+
readonly level: Exclude<LogLevel, "silent">;
|
|
33
|
+
readonly category: LogCategory;
|
|
34
|
+
readonly message: string;
|
|
35
|
+
readonly context: LogContext;
|
|
36
|
+
readonly data?: Record<string, unknown>;
|
|
37
|
+
readonly timestamp: number;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Logger port for structured logging.
|
|
41
|
+
*
|
|
42
|
+
* This is a driven (secondary) port - domain logic calls out to it,
|
|
43
|
+
* implementations are injected via dependency injection.
|
|
44
|
+
*
|
|
45
|
+
* Implementations must handle:
|
|
46
|
+
* - Level filtering (only emit logs at or above configured level)
|
|
47
|
+
* - Category filtering (optionally filter by category)
|
|
48
|
+
* - Output formatting (console, JSON, custom)
|
|
49
|
+
*
|
|
50
|
+
* This port enables:
|
|
51
|
+
* - NoOpLogger: Zero overhead when disabled (production, silent mode)
|
|
52
|
+
* - ConsoleLogger: Human-readable or JSON output (development)
|
|
53
|
+
* - TestLogger: Capture logs for assertion in tests
|
|
54
|
+
* - Custom loggers: User-provided implementations (Winston, Pino, etc.)
|
|
55
|
+
*
|
|
56
|
+
* All methods return void - logging is fire-and-forget.
|
|
57
|
+
* Implementations should never throw.
|
|
58
|
+
*/
|
|
59
|
+
export interface Logger {
|
|
60
|
+
/**
|
|
61
|
+
* Log at error level - critical failures preventing operation.
|
|
62
|
+
*
|
|
63
|
+
* @param category - Area of concern for filtering
|
|
64
|
+
* @param message - Human-readable event description
|
|
65
|
+
* @param context - Request context for correlation (testId, scenarioId, etc.)
|
|
66
|
+
* @param data - Optional structured data for the event
|
|
67
|
+
*/
|
|
68
|
+
error(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
69
|
+
/**
|
|
70
|
+
* Log at warn level - potential issues that may cause problems.
|
|
71
|
+
*
|
|
72
|
+
* @param category - Area of concern for filtering
|
|
73
|
+
* @param message - Human-readable event description
|
|
74
|
+
* @param context - Request context for correlation
|
|
75
|
+
* @param data - Optional structured data for the event
|
|
76
|
+
*/
|
|
77
|
+
warn(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
78
|
+
/**
|
|
79
|
+
* Log at info level - operation flow and key events.
|
|
80
|
+
*
|
|
81
|
+
* @param category - Area of concern for filtering
|
|
82
|
+
* @param message - Human-readable event description
|
|
83
|
+
* @param context - Request context for correlation
|
|
84
|
+
* @param data - Optional structured data for the event
|
|
85
|
+
*/
|
|
86
|
+
info(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
87
|
+
/**
|
|
88
|
+
* Log at debug level - detailed decision logic.
|
|
89
|
+
*
|
|
90
|
+
* @param category - Area of concern for filtering
|
|
91
|
+
* @param message - Human-readable event description
|
|
92
|
+
* @param context - Request context for correlation
|
|
93
|
+
* @param data - Optional structured data for the event
|
|
94
|
+
*/
|
|
95
|
+
debug(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
96
|
+
/**
|
|
97
|
+
* Log at trace level - request/response bodies, verbose details.
|
|
98
|
+
*
|
|
99
|
+
* @param category - Area of concern for filtering
|
|
100
|
+
* @param message - Human-readable event description
|
|
101
|
+
* @param context - Request context for correlation
|
|
102
|
+
* @param data - Optional structured data for the event
|
|
103
|
+
*/
|
|
104
|
+
trace(category: LogCategory, message: string, context: LogContext, data?: Record<string, unknown>): void;
|
|
105
|
+
/**
|
|
106
|
+
* Check if a specific level would be logged.
|
|
107
|
+
* Enables conditional expensive operations before logging.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* if (logger.isEnabled('trace')) {
|
|
111
|
+
* logger.trace('request', 'body', ctx, { body: JSON.stringify(large) });
|
|
112
|
+
* }
|
|
113
|
+
*
|
|
114
|
+
* @param level - The log level to check
|
|
115
|
+
* @returns true if logging at this level is enabled
|
|
116
|
+
*/
|
|
117
|
+
isEnabled(level: Exclude<LogLevel, "silent">): boolean;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/ports/driven/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhF;;;GAGG;AACH,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,UAAU,GACV,UAAU,GACV,UAAU,GACV,OAAO,GACP,UAAU,GACV,SAAS,CAAC;AAEd;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,MAAM;IACrB;;;;;;;OAOG;IACH,KAAK,CACH,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAAC;IAER;;;;;;;OAOG;IACH,IAAI,CACF,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAAC;IAER;;;;;;;OAOG;IACH,IAAI,CACF,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAAC;IAER;;;;;;;OAOG;IACH,KAAK,CACH,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAAC;IAER;;;;;;;OAOG;IACH,KAAK,CACH,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAAC;IAER;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC;CACxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ScenaristMockWithParams, ScenaristResponse, HttpRequestContext, ScenaristResult } from "../../types/index.js";
|
|
2
|
+
import { ScenaristError } from "../../types/errors.js";
|
|
2
3
|
/**
|
|
3
4
|
* Error type for response selection failures.
|
|
5
|
+
* @deprecated Use ScenaristError with ErrorCodes.NO_MOCK_FOUND instead
|
|
4
6
|
*/
|
|
5
7
|
export declare class ResponseSelectionError extends Error {
|
|
6
8
|
constructor(message: string);
|
|
@@ -29,6 +31,6 @@ export interface ResponseSelector {
|
|
|
29
31
|
* @param mocks - Candidate mocks with extracted params (already filtered by URL/method)
|
|
30
32
|
* @returns ScenaristResult with selected ScenaristResponse or error if no match found
|
|
31
33
|
*/
|
|
32
|
-
selectResponse(testId: string, scenarioId: string, context: HttpRequestContext, mocks: ReadonlyArray<ScenaristMockWithParams>): ScenaristResult<ScenaristResponse,
|
|
34
|
+
selectResponse(testId: string, scenarioId: string, context: HttpRequestContext, mocks: ReadonlyArray<ScenaristMockWithParams>): ScenaristResult<ScenaristResponse, ScenaristError>;
|
|
33
35
|
}
|
|
34
36
|
//# sourceMappingURL=response-selector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-selector.d.ts","sourceRoot":"","sources":["../../../src/ports/driven/response-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EAChB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"response-selector.d.ts","sourceRoot":"","sources":["../../../src/ports/driven/response-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;OAQG;IACH,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,kBAAkB,EAC3B,KAAK,EAAE,aAAa,CAAC,uBAAuB,CAAC,GAC5C,eAAe,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;CACvD"}
|
package/dist/ports/index.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export type { RequestContext } from "./driven/request-context.js";
|
|
|
5
5
|
export type { ResponseSelector } from "./driven/response-selector.js";
|
|
6
6
|
export type { SequenceTracker, SequencePosition, } from "./driven/sequence-tracker.js";
|
|
7
7
|
export type { StateManager } from "./driven/state-manager.js";
|
|
8
|
+
export type { Logger, LogLevel, LogCategory, LogContext, LogEntry, } from "./driven/logger.js";
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,YAAY,EACV,eAAe,EACf,gBAAgB,GACjB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,YAAY,EACV,eAAe,EACf,gBAAgB,GACjB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,YAAY,EACV,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAU,EACV,QAAQ,GACT,MAAM,oBAAoB,CAAC"}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import type { ScenaristScenarios } from "./scenario.js";
|
|
2
|
+
/**
|
|
3
|
+
* How errors should be handled when they occur.
|
|
4
|
+
*
|
|
5
|
+
* - `throw`: Throw ScenaristError (strict - test fails with clear message)
|
|
6
|
+
* - `warn`: Log at warn level, return undefined (let strictMode decide next step)
|
|
7
|
+
* - `ignore`: Return undefined silently (let strictMode decide next step)
|
|
8
|
+
*/
|
|
9
|
+
export type ErrorBehavior = "throw" | "warn" | "ignore";
|
|
10
|
+
/**
|
|
11
|
+
* Configuration for how different error types should be handled.
|
|
12
|
+
* Default is 'throw' for all (strict by default).
|
|
13
|
+
*/
|
|
14
|
+
export type ErrorBehaviors = {
|
|
15
|
+
/** How to handle when no mock matches a request. Default: 'throw' */
|
|
16
|
+
readonly onNoMockFound: ErrorBehavior;
|
|
17
|
+
/** How to handle when a sequence is exhausted. Default: 'throw' */
|
|
18
|
+
readonly onSequenceExhausted: ErrorBehavior;
|
|
19
|
+
/** How to handle when x-scenarist-test-id header is missing. Default: 'throw' */
|
|
20
|
+
readonly onMissingTestId: ErrorBehavior;
|
|
21
|
+
};
|
|
2
22
|
/**
|
|
3
23
|
* Configuration for the scenario management system.
|
|
4
24
|
* All properties are readonly for immutability.
|
|
@@ -35,6 +55,11 @@ export type ScenaristConfig = {
|
|
|
35
55
|
* The default test ID to use when no x-scenarist-test-id header is present.
|
|
36
56
|
*/
|
|
37
57
|
readonly defaultTestId: string;
|
|
58
|
+
/**
|
|
59
|
+
* How different error types should be handled.
|
|
60
|
+
* Default is 'throw' for all (strict by default).
|
|
61
|
+
*/
|
|
62
|
+
readonly errorBehaviors: ErrorBehaviors;
|
|
38
63
|
};
|
|
39
64
|
/**
|
|
40
65
|
* Partial config for user input - missing values will use defaults.
|
|
@@ -66,5 +91,9 @@ export type ScenaristConfigInput<T extends ScenaristScenarios = ScenaristScenari
|
|
|
66
91
|
*/
|
|
67
92
|
readonly scenarios: T;
|
|
68
93
|
readonly defaultTestId?: string;
|
|
94
|
+
/**
|
|
95
|
+
* Optional error behavior overrides. Missing values use 'throw' as default.
|
|
96
|
+
*/
|
|
97
|
+
readonly errorBehaviors?: Partial<ErrorBehaviors>;
|
|
69
98
|
};
|
|
70
99
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE;QAClB,kEAAkE;QAClE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,kEAAkE;QAClE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;IAEF;;OAEG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAExD;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,mEAAmE;IACnE,QAAQ,CAAC,mBAAmB,EAAE,aAAa,CAAC;IAC5C,iFAAiF;IACjF,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE;QAClB,kEAAkE;QAClE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,kEAAkE;QAClE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;IAEF;;OAEG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,oBAAoB,CAC9B,CAAC,SAAS,kBAAkB,GAAG,kBAAkB,IAC/C;IACF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC;IAC3D;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IACtB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;OAEG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CACnD,CAAC"}
|